package com.yanqu.road.server.gameplayer.module.activity.washe;

import com.alibaba.fastjson.JSON;
import com.google.protobuf.InvalidProtocolBufferException;
import com.yanqu.road.entity.activity.area.wase.AreaWashePkConfig;
import com.yanqu.road.entity.activity.args.WasheScoreRankArgs;
import com.yanqu.road.entity.activity.washe.config.*;
import com.yanqu.road.entity.activity.washe.data.*;
import com.yanqu.road.entity.config.badge.BadgeConfig;
import com.yanqu.road.entity.config.expression.ExpressionInfo;
import com.yanqu.road.entity.config.goods.GoodsInfo;
import com.yanqu.road.entity.config.goods.MallInfo;
import com.yanqu.road.entity.enums.*;
import com.yanqu.road.entity.enums.washe.*;
import com.yanqu.road.entity.log.LogWasheBox;
import com.yanqu.road.entity.log.LogWasheGameOver;
import com.yanqu.road.entity.log.LogWasheRmbMall;
import com.yanqu.road.entity.player.UserBadge;
import com.yanqu.road.logic.bussiness.activity.WasheBusiness;
import com.yanqu.road.logic.config.GameConfig;
import com.yanqu.road.logic.pb.WashePb2;
import com.yanqu.road.pb.activity.WasheProto;
import com.yanqu.road.server.gameplayer.GamePlayer;
import com.yanqu.road.server.gameplayer.module.activity.luckydraw.LuckyDrawModule;
import com.yanqu.road.server.gameplayer.module.base.GeneralModule;
import com.yanqu.road.server.gameplayer.module.player.*;
import com.yanqu.road.server.gameplayer.module.sign.SignModule;
import com.yanqu.road.server.gameplayer.module.verification.VerificationModule;
import com.yanqu.road.server.gameplayer.module.xiaomian.XiaoMianModule;
import com.yanqu.road.server.logic.season.args.WasheJinBiaoPeakRankArgs;
import com.yanqu.road.server.logic.season.args.WasheTimeLimitTaskArgs;
import com.yanqu.road.server.manger.activity.NormalActivityMgr;
import com.yanqu.road.server.manger.activity.area.AreaWasePkMgr;
import com.yanqu.road.server.manger.activity.washe.WasheMgr;
import com.yanqu.road.server.manger.config.BadgeConfigMgr;
import com.yanqu.road.server.manger.config.GoodsMgr;
import com.yanqu.road.server.manger.config.SystemOpenMgr;
import com.yanqu.road.server.manger.log.AutoLogMgr;
import com.yanqu.road.server.manger.player.ChatConfigMgr;
import com.yanqu.road.server.pb.PlayerPb;
import com.yanqu.road.server.pb.WashePb;
import com.yanqu.road.server.protocol.ChannelProtocol;
import com.yanqu.road.server.protocol.ClientProtocol;
import com.yanqu.road.server.protocol.GameErrorCode;
import com.yanqu.road.utils.RandomHelper;
import com.yanqu.road.utils.date.DateHelper;
import com.yanqu.road.utils.property.Property;
import com.yanqu.road.utils.property.PropertyHelper;
import com.yanqu.road.utils.string.StringUtils;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;

public class WasheModule extends GeneralModule {

    private Random random = new Random();

    // 玩家数据
    private WasheUserData washeUserData;
    private WasheUserJinBiaoData washeUserJinBiaoData;

    // 对局记录
    private AtomicLong maxRecordId;
    private Map<Integer, List<WasheBattleRecord>> recordListMap;

    // 荣誉瞬间
    private WasheHonorMoment honorMoment;

    // 历史数据记录
    private WasheHistory history;

    public WasheModule(GamePlayer player) {
        super(player);
    }

    @Override
    public boolean loadData() {

        WasheConfig washeConfig = WasheMgr.getWasheConfig();
        int limit = washeConfig != null ? washeConfig.getMaxRecordNum() : 50;

        // 读库
        washeUserData = WasheBusiness.getWasheUserData(getUserId());
        washeUserJinBiaoData = WasheBusiness.getWasheUserJinBiaoData(getUserId());
        honorMoment = WasheBusiness.getWasheHonorMoment(getUserId());
        history = WasheBusiness.getWasheHistory(getUserId());

        // 初始化部分数据（除了userData都直接初始化）
        if (recordListMap == null) {
            recordListMap = new ConcurrentHashMap<>();
        }
        for (eWasheRecordType recordType : eWasheRecordType.values()) {
            recordListMap.put(recordType.getValue(), WasheBusiness.getWasheBattleRecordList(getUserId(), recordType.getValue(), limit));
        }

        if (honorMoment == null) {
            honorMoment = new WasheHonorMoment();
            honorMoment.setUserId(getUserId());
            honorMoment.setHonorMomentTempMap(new ConcurrentHashMap<>());
            honorMoment.setLastGameMomentTempList(new ArrayList<>());
            honorMoment.setInsertOption();
        }
        if (history == null) {
            history = new WasheHistory();
            history.setUserId(getUserId());
            history.setSeasonHistoryTempMap(new ConcurrentHashMap<>());
            history.setHistoryTempMap(new ConcurrentHashMap<>());
            history.setLastGameHistoryTempMap(new ConcurrentHashMap<>());
            history.setCardUseTimesMap(new ConcurrentHashMap<>());
            history.setInsertOption();
        }

        // 初始化下标
        long maxTempRecordId = 0;
        if (!recordListMap.isEmpty()) {
            for (List<WasheBattleRecord> records : recordListMap.values()) {
                for (WasheBattleRecord record : records) {
                    maxTempRecordId = Math.max(maxTempRecordId, record.getNo());
                }
            }
        }
        maxRecordId = new AtomicLong(maxTempRecordId);
        return true;
    }

    @Override
    public boolean afterLoadData() {
        return true;
    }

    @Override
    public boolean saveData() {

        if (washeUserData != null) {
            if (washeUserData.isInsertOption()) {
                WasheBusiness.addWasheUserData(washeUserData);
            } else if (washeUserData.isUpdateOption()) {
                WasheBusiness.updateWasheUserData(washeUserData);
            }
        }

        if (washeUserJinBiaoData != null) {
            if (washeUserJinBiaoData.isInsertOption()) {
                WasheBusiness.addWasheUserJinBiaoData(washeUserJinBiaoData);
            } else if (washeUserJinBiaoData.isUpdateOption()) {
                WasheBusiness.updateWasheUserJinBiaoData(washeUserJinBiaoData);
            }
        }

        ConcurrentHashMap<Integer, List<WasheBattleRecord>> newRecordListMap = new ConcurrentHashMap<>(recordListMap);
        for (List<WasheBattleRecord> recordList : newRecordListMap.values()) {
            for (WasheBattleRecord record : recordList) {
                if (record.isInsertOption()) {
                    WasheBusiness.addWasheBattleRecord(record);
                }
            }
        }

        if (honorMoment.isInsertOption()) {
            WasheBusiness.addWasheHonorMoment(honorMoment);
        } else if (honorMoment.isUpdateOption()) {
            WasheBusiness.updateWasheHonorMoment(honorMoment);
        }

        if (history.isInsertOption()) {
            WasheBusiness.addWasheHistory(history);
        } else if (history.isUpdateOption()) {
            WasheBusiness.updateWasheHistory(history);
        }

        return true;
    }

    @Override
    public void afterLogin() {

        refreshData();

        WasheConfig config = WasheMgr.getWasheConfig();
        WasheUserData userData = getWasheUserData();
        if (config != null && userData != null) {
            if (userData.getDataSeason() == WasheConfig.SEASON_ID_NULL || userData.getDataSeason() == config.getSeasonId()) {
                player.notifySeasonReward(eSeasonRewardType.WasheScoreRank, userData.getScore());
                player.notifyListener(eGamePlayerEventType.WasheScoreSmallRank.getValue(), new WasheScoreRankArgs(userData.getScore()));
            }
        }

        WasheUserJinBiaoData jinBiaoData = getWasheUserJinBiaoData();
        if (config != null && jinBiaoData != null) {
            if (jinBiaoData.getDataSeason() == WasheConfig.SEASON_ID_NULL || jinBiaoData.getDataSeason() == config.getSeasonId()) {
                player.notifySeasonReward(eSeasonRewardType.JinBiaoScoreRank, jinBiaoData.getScore());
            }
        }

    }

    public void refreshData() {

        WasheConfig config = WasheMgr.getWasheConfig();
        WasheUserData userData = getWasheUserData();
        if (config != null && userData != null) {
            checkClearOldData(config, userData);
        }

        initUserData();
        syncConfigAndData();
        checkGameOverReward();
    }

    private synchronized void initUserData() {

        if (!SystemOpenMgr.systemOpen(player, eSystemId.WasheActivity.getValue())) {
            return;
        }

        WasheConfig washeConfig = WasheMgr.getWasheConfig();
        if (washeConfig == null) {
            return;
        }

        // 初始化数据
        if (washeUserData == null) {
            WasheUserData userData = new WasheUserData();
            userData.setUserId(getUserId());
            userData.setScore(0);
            userData.setUnlockCard(new HashSet<>());
            userData.setUnlockSkill(new HashSet<>());
            userData.setSeasonScoreMap(new ConcurrentHashMap<>());
            userData.setSeasonTopScoreMap(new ConcurrentHashMap<>());
            userData.setBuffTimes(-1);
            userData.setBuffCollectTimes(0);
            userData.setSilverSet(new HashSet<>());
            userData.setGoldSet(new HashSet<>());
            userData.setBoxDataList(new ArrayList<>());
            userData.setDataSeason(WasheConfig.SEASON_ID_NULL);
            userData.setGuide(true);
            userData.setPlayTimes(0);
            userData.setContinueFailTimes(0);
            userData.setSeasonPlayTime(0);
            userData.setTodayPlayTime(0);
            userData.setDayResetTime(DateHelper.getTodayZeroTimeStamp());
            userData.setDayPlayTimes(0);
            userData.setDaySurrenderTimes(0);
            userData.setContinueWinTimes(0);
            // userData.setSelectedSkill();
            userData.setLinkGuide(false);
            userData.setDecorationMap(new ConcurrentHashMap<>());
            userData.setInsertOption();
            washeUserData = userData;
        }

        if (washeUserJinBiaoData == null) {
            WasheUserJinBiaoData jinBiaoData = new WasheUserJinBiaoData();
            jinBiaoData.setUserId(getUserId());
            // 获取当前用户的赛季
            jinBiaoData.setDataSeason(washeUserData.getDataSeason());
            jinBiaoData.setEnergy(washeConfig.getJinBiaoDaySpiritNum());
            jinBiaoData.setScore(0);
            jinBiaoData.setContinueWinTimes(0);
            jinBiaoData.setDayResetTime(DateHelper.getTodayZeroTimeStamp());
            jinBiaoData.setInsertOption();
            washeUserJinBiaoData = jinBiaoData;
        }

        // 解锁免费卡片
        Set<Integer> unlockCard = washeUserData.getUnlockCard();
        for (WasheCardConfig cardConfig : washeConfig.getCardConfigMap().values()) {
            if (cardConfig.isFree()) {
                unlockCard.add(cardConfig.getCardId());
            }
        }
        // 解锁免费技能
        List<Integer> freeSkillList = washeConfig.getFreeSkillList();
        washeUserData.getUnlockSkill().addAll(freeSkillList);
        // 设置默认盘面技能
        if (washeUserData.getSelectedSkill().size() != 2 && freeSkillList.size() >= 2) {
            List<Integer> selectList = new ArrayList<>();
            for (int i = 0; i < 2; i++) {
                selectList.add(freeSkillList.get(i));
            }
            washeUserData.setSelectedSkill(selectList);
        }

        washeUserData.setUpdateOption();
    }

    private void syncConfigAndData() {
        WasheConfig config = WasheMgr.getWasheConfig();
        if (config != null) {
            WasheProto.WasheSyncConfigRespMsg.Builder configBuilder = WashePb.parseWasheSyncConfigRespMsg(config, player.getLanguage());
            player.sendPacket(ClientProtocol.U_WASHE_SYNC_CONFIG, configBuilder);
        }

        WasheUserData userData = getWasheUserData();
        if (userData != null && config != null) {
            syncUserData(config, userData, getWasheUserJinBiaoData());
        }
    }

    public synchronized WasheUserData getWasheUserData() {

        if (washeUserData != null && System.currentTimeMillis() - washeUserData.getDayResetTime() > DateHelper.DAY_MILLIONS) {
            // 每日重置
            washeUserData.setDayResetTime(DateHelper.getTodayZeroTimeStamp());
            washeUserData.setTodayPlayTime(0);
            washeUserData.setDayPlayTimes(0);
            washeUserData.setDaySurrenderTimes(0);
        }

        return washeUserData;
    }

    public synchronized WasheUserJinBiaoData getWasheUserJinBiaoData() {
        WasheConfig washeConfig = WasheMgr.getWasheConfig();
        if (washeConfig != null && washeUserJinBiaoData != null && System.currentTimeMillis() - washeUserJinBiaoData.getDayResetTime() > DateHelper.DAY_MILLIONS) {
            // 每日重置
            washeUserJinBiaoData.setDayResetTime(DateHelper.getTodayZeroTimeStamp());
            washeUserJinBiaoData.setEnergy(washeConfig.getJinBiaoDaySpiritNum());
            washeUserJinBiaoData.setContinueWinTimes(0);
        }
        return washeUserJinBiaoData;
    }

    public void syncUserData(WasheConfig config, WasheUserData userData, WasheUserJinBiaoData jinBiaoData) {
        WasheProto.WasheSyncUserRespMsg.Builder userBuilder = WasheProto.WasheSyncUserRespMsg.newBuilder();
        userBuilder.setUserData(WashePb.parseWasheUserDataMsg(config, userData, jinBiaoData, null));
        player.sendPacket(ClientProtocol.U_WASHE_SYNC_USER_DATA, userBuilder);
    }

    private void checkClearOldData(WasheConfig config, WasheUserData userData) {
        // 清空旧赛季宝箱
        clearOldBox(config, userData);
        // 重导活动清空没配置现金礼包
        clearOldMall(config, userData);
        // 旧版宝箱数据转换新版
        channelOldBox(config, userData);
    }

    private void channelOldBox(WasheConfig config, WasheUserData userData) {
        boolean change = false;

        List<WasheBoxData> boxDataList = userData.getBoxDataList();
        for (int i = 0; i < boxDataList.size(); i++) {
            WasheBoxData boxData = boxDataList.get(i);
            if (StringUtils.isNullOrEmpty(boxData.getReward())) {
                // 找宝箱配置
                WasheBoxConfig boxConfig = null;
                for (WasheBoxConfig tmpBoxConfig : config.getWasheBoxConfigList(boxData.getSeasonId())) {
                    if (tmpBoxConfig.getSeasonId() == boxData.getSeasonId() && tmpBoxConfig.getBoxId() == boxData.getBoxId()) {
                        boxConfig = tmpBoxConfig;
                        break;
                    }
                }
                // 找不到配置的清空掉
                if (boxConfig == null) {
                    boxDataList.remove(i--);

                    change = true;
                    continue;
                }

                // 拿奖励设置进去
                String reward;
                if (!eWasheFunction.NewBoxConfig.isOpen(config.getVersion())) {
                    int rewardIndex = RandomHelper.getRandomIndexByWeight(boxConfig.getWeightList(), random);
                    reward = boxConfig.getRewardList().get(rewardIndex);
                } else {
                    reward = PropertyHelper.parsePropertyToString(PropertyHelper.parseNewStringToProperty(boxConfig.getNewrewards()));
                }

                boxData.setReward(reward);
                change = true;
            }
        }

        if (change) {
            userData.setUpdateOption();
        }
    }

    // ========================================

    /**
     * 检查赛季切换
     */
    private boolean checkSeasonChange() {
        WasheUserData userData = getWasheUserData();
        WasheUserJinBiaoData jinBiaoData = getWasheUserJinBiaoData();
        if (userData.isGuide()) {
            // 新手阶段不能切换赛季
            return false;
        }

        WasheConfig config = WasheMgr.getWasheConfig();
        if (config == null || config.getSeasonId() <= userData.getDataSeason()) {
            // 赛季ID没有更大
            return false;
        }

        // 连续继承，但是都按当前赛季配置
        long tmpScore = userData.getScore();
        int times = userData.getDataSeason() == WasheConfig.SEASON_ID_NULL ? 1 : config.getSeasonId() - userData.getDataSeason(); // 无赛季继承到哪都是直接继承1次
        for (int i = 0; i < times; i++) {

            WasheRankConfig resetConfig = null;
            Map<Integer, WasheRankConfig> rankConfigMap = config.getRankConfigMap();
            for (WasheRankConfig rankConfig : rankConfigMap.values()) {
                if (rankConfig.getEndReset() <= 0) {
                    continue;
                }
                if (rankConfig.getSeasonId() != WasheConfig.SEASON_ID_NULL && tmpScore >= rankConfig.getEndReset()) { // 需要达到重置所需分数
                    if (resetConfig == null || resetConfig.getRankId() < rankConfig.getRankId()) { // 段位ID比当前高
                        resetConfig = rankConfig;
                    }
                }
            }

            if (resetConfig != null) {
                tmpScore = resetConfig.getRankScore();
            } else {
                log.error("washe season change error! userId {} score {} isGuide {} dataSeason {}, index {}.",
                        userData.getUserId(), userData.getScore(), userData.isGuide(), userData.getDataSeason(), i);
                throw new RuntimeException("washe no reset config !!!");
            }

        }

        // 最终继承结果
        userData.setDataSeason(config.getSeasonId());
        changeScore(config, userData, tmpScore - userData.getScore());

        // 锦标赛数据
        jinBiaoData.setDataSeason(config.getSeasonId());
        // 清空下锦标赛积分
        changeJinBiaoScore(config, jinBiaoData, -jinBiaoData.getScore());

        // 继承前后可能勋章
        WasheRankConfig rankConfig = config.getWasheRankConfig(userData.getScore(), userData.isGuide());
        if (rankConfig != null && rankConfig.getMedal() != 0) {
            player.getModule(BadgeModule.class).addBadge(rankConfig.getMedal(), eBadgeType.Washe.getValue());
        }

        // 清空旧赛季数据
        checkClearOldData(config, userData);

        return true;
    }

    private void clearOldBox(WasheConfig config, WasheUserData userData) {
        List<WasheBoxData> boxDataList = userData.getBoxDataList();
        int oldSize = boxDataList.size();

        for (int i = 0; i < boxDataList.size(); i++) {
            WasheBoxData boxData = boxDataList.get(i);
            if (boxData.getSeasonId() > WasheConfig.SEASON_ID_NULL && boxData.getSeasonId() != config.getSeasonId()) {
                boxDataList.remove(i);
                i--;
            }
        }

        if (boxDataList.size() != oldSize) {
            userData.setUpdateOption();
        }
    }

    private void clearOldMall(WasheConfig config, WasheUserData userData) {
        Map<Integer, WasheRmbMallData> mallDataMap = userData.getRmbMallMap();
        int oldSize = mallDataMap.size();

        Map<Integer, MallInfo> mallInfoMap = NormalActivityMgr.getMallInfoTypeMap(config.getActivityInfo().getActivityId(), eShopType.WasheRmbMall.getValue());
        for (Map.Entry<Integer, WasheRmbMallData> entry : mallDataMap.entrySet()) {
            if (!mallInfoMap.containsKey(entry.getKey())) {
                mallDataMap.remove(entry.getKey());
            }
        }

        if (mallDataMap.size() != oldSize) {
            userData.setUpdateOption();
        }
    }

    /**
     * 检查游戏结束奖励
     */
    private void checkGameOverReward() {
        WasheLastResultData lastResultData = WasheMgr.getLastResultData(getUserId());
        if (lastResultData == null || lastResultData.isHandle()) {
            return;
        }
        // 先改成已处理，再处理
        lastResultData.setHandle(true);

        // 没配置 或者 数据跨赛季了 不管了
        WasheConfig config = WasheMgr.getWasheConfig();
        if (config == null) {
            log.error("washe checkGameOverReward error! no reward! userId {}", getUserId());
            return;
        }

        try {
            byte[] decode = Base64.getDecoder().decode(lastResultData.getMsgData());
            WasheProto.WasheGameOverMsg overMsg = WasheProto.WasheGameOverMsg.parseFrom(decode);
            WasheProto.WasheGameOverMsg.Builder builder = gameOverAction(overMsg);
            // 处理完修改下结果
            byte[] bytes = builder.build().toByteArray();
            String msgData = Base64.getEncoder().encodeToString(bytes);
            lastResultData.setMsgData(msgData);
        } catch (InvalidProtocolBufferException e) {
            e.printStackTrace();
        }
    }

    /**
     * 使用buff药
     */
    public void useBuffItem(int goodsId, int num) {
        WasheUserData userData = getWasheUserData();
        if (userData == null) {
            log.info("washe use buff item error! no user data! userId {} itemId {} num {}", getUserId(), goodsId, num);
            return;
        }

        GoodsInfo goodsInfo = GoodsMgr.getGoodsById(goodsId);
        if (goodsInfo == null) {
            log.info("washe use buff item error! no goods info! userId {} itemId {} num {}", getUserId(), goodsId, num);
            return;
        }

        int times = goodsInfo.getParamList().get(1).intValue();
        int totalTime = times * num;

        int buffTimes = userData.getBuffTimes();
        if (buffTimes > 0) {
            userData.setBuffTimes(buffTimes + totalTime);
        } else {
            userData.setBuffTimes(totalTime); // buffTimes可能为-1，不能直接加
        }
        userData.setBuffCollectTimes(0);
    }

    /**
     * 检查获得卡片
     */
    public void checkGetWasheCard(int goodsId, long num) {

        WasheConfig config = WasheMgr.getWasheConfig();
        if (config == null) {
            log.error("user {} check unlock washe card fail! goodsId {}, no washe config.", getUserId(), goodsId);
            return;
        }

        WasheCardConfig cardConfig = config.getItemCardConfigMap().get(goodsId);
        if (cardConfig == null) {
            log.error("user {} check unlock washe card fail! goodsId {}, no card config.", getUserId(), goodsId);
            return;
        }

        WasheUserData userData = getWasheUserData();
        if (userData == null) {
            log.error("user {} check unlock washe card fail! goodsId {}, no user data.", getUserId(), goodsId);
        } else {

            // 解锁卡片
            Set<Integer> unlockCard = userData.getUnlockCard();
            if (!unlockCard.contains(cardConfig.getCardId())) {
                unlockCard.add(cardConfig.getCardId());
                userData.setUpdateOption();
                // 同步解锁卡片
                WasheProto.WasheSyncUnlockCardRespMsg.Builder builder = WasheProto.WasheSyncUnlockCardRespMsg.newBuilder();
                builder.setCardId(cardConfig.getCardId());
                player.sendPacket(ClientProtocol.U_WASHE_SYNC_UNLOCK_CARD, builder);
            }
        }

        // 历史记录
        Map<Integer, Long> typeValueMap = new HashMap<>();
        typeValueMap.put(eWasheHonorMomentType.GetCardCount.getIntValue(), num);
        if (userData != null) {
            typeValueMap.put(eWasheHonorMomentType.UnlockCardKind.getIntValue(), (long) userData.getUnlockCard().size());
        }
        changeHistory(typeValueMap);
    }


    /**
     * 检查获得盘面技能
     */
    public void checkGetWasheSkill(int goodsId, long num) {

        WasheConfig config = WasheMgr.getWasheConfig();
        if (config == null) {
            log.error("user {} check unlock washe skill fail! goodsId {}, no washe config.", getUserId(), goodsId);
            return;
        }

        WasheSkillConfig skillConfig = config.getItemSkillConfigMap().get(goodsId);
        if (skillConfig == null) {
            log.error("user {} check unlock washe skill fail! goodsId {}, no skill config.", getUserId(), goodsId);
            return;
        }

        WasheUserData userData = getWasheUserData();
        if (userData == null) {
            log.error("user {} check unlock washe skill fail! goodsId {}, no user data.", getUserId(), goodsId);
        } else {

            // 解锁卡片
            Set<Integer> unlockSkill = userData.getUnlockSkill();
            if (!unlockSkill.contains(skillConfig.getSkillId())) {
                unlockSkill.add(skillConfig.getSkillId());
                userData.setUpdateOption();
                // 同步解锁盘面技能
                WasheProto.WasheSyncUnlockSkillRespMsg.Builder builder = WasheProto.WasheSyncUnlockSkillRespMsg.newBuilder();
                builder.setSkillId(skillConfig.getSkillId());
                player.sendPacket(ClientProtocol.U_WASHE_SYNC_UNLOCK_SKILL, builder);
            }
        }

        /*
        // 历史记录
        Map<Integer, Long> typeValueMap = new HashMap<>();
        typeValueMap.put(eWasheHonorMomentType.GetCardCount.getIntValue(), num);
        if (userData != null) {
            typeValueMap.put(eWasheHonorMomentType.UnlockCardKind.getIntValue(), (long) userData.getUnlockCard().size());
        }
        changeHistory(typeValueMap);
        */
    }

    /**
     * 荣誉点变化（暂时public）
     *
     * @return 真实变化分数（新手阶段无法超过新手最高分）
     */
    public long changeScore(WasheConfig config, WasheUserData userData, long changeValue) {
        long oldScore = userData.getScore();
        boolean guide = userData.isGuide();
        long maxScore = guide ? config.getNewHandScore() : Long.MAX_VALUE;
        long minScore = guide ? 0 : config.getNewHandScore();

        int seasonId = config.getSeasonId();

        // 分数上下限限制
        long newScore = oldScore + changeValue;
        if (newScore > maxScore) newScore = maxScore;
        if (newScore < minScore) newScore = minScore;

        // 修改分数
        userData.setScore(newScore);

        if (seasonId > WasheConfig.SEASON_ID_NULL) {
            // 记录最终分数
            userData.getSeasonScoreMap().put(seasonId, newScore);
            // 记录最高分数
            ConcurrentHashMap<Integer, Long> seasonTopScoreMap = userData.getSeasonTopScoreMap();
            if (newScore > seasonTopScoreMap.getOrDefault(seasonId, 0L)) {
                seasonTopScoreMap.put(seasonId, newScore);
            }
        }

        // 勋章
        WasheRankConfig oldRankConfig = config.getWasheRankConfig(oldScore, guide);
        WasheRankConfig newRankConfig = config.getWasheRankConfig(newScore, guide);
        if (newRankConfig.getMedal() != oldRankConfig.getMedal() && newRankConfig.getMedal() != 0) { // 策划分数不会掉到没有勋章的段位
            player.getModule(BadgeModule.class).addBadge(newRankConfig.getMedal(), eBadgeType.Washe.getValue());
        }

        // 成就、榜单
        if (userData.getDataSeason() == WasheConfig.SEASON_ID_NULL || userData.getDataSeason() == config.getSeasonId()) {
            player.notifySeasonReward(eSeasonRewardType.WasheGetScoreZhanLing, changeValue);
            player.notifySeasonReward(eSeasonRewardType.WasheScoreRank, userData.getScore());
            player.notifySeasonReward(eSeasonRewardType.WasheNewHandScoreArch, userData.getScore());
            player.notifySeasonReward(eSeasonRewardType.WasheScoreArch, userData.getScore());
            player.notifyListener(eGamePlayerEventType.WasheScoreSmallRank.getValue(), new WasheScoreRankArgs(userData.getScore()));
        }

        // 历史记录
        Map<Integer, Long> typeValueMap = new HashMap<>();
        typeValueMap.put(eWasheHonorMomentType.HonorPoint.getIntValue(), newScore);
        changeHistory(typeValueMap);

        userData.setUpdateOption();

        return newScore - oldScore;
    }

    /**
     * 积分赛积分变化
     *
     * @return 真实变化积分
     */
    public long changeJinBiaoScore(WasheConfig config, WasheUserJinBiaoData jinBiaoData, long changeValue) {
        long oldScore = jinBiaoData.getScore();
        long maxScore = Long.MAX_VALUE;
        long minScore = Long.MIN_VALUE;
        // 分数上下限限制
        long newScore = Math.max(minScore, Math.min(maxScore, oldScore + changeValue));

        // 修改分数
        jinBiaoData.setScore(newScore);

        int seasonId = config.getSeasonId();
        if (seasonId > WasheConfig.SEASON_ID_NULL) {
            // 记录最终分数
            jinBiaoData.getSeasonScoreMap().put(seasonId, newScore);
            // 记录最高分数
            ConcurrentHashMap<Integer, Long> seasonTopScoreMap = jinBiaoData.getSeasonTopScoreMap();
            if (!seasonTopScoreMap.containsKey(seasonId) || newScore > seasonTopScoreMap.get(seasonId)) {
                seasonTopScoreMap.put(seasonId, newScore);
            }
        }

        // 成就、榜单
        if (jinBiaoData.getDataSeason() == WasheConfig.SEASON_ID_NULL || jinBiaoData.getDataSeason() == config.getSeasonId()) {
            player.notifySeasonReward(eSeasonRewardType.JinBiaoScoreRank, jinBiaoData.getScore());
        }

        jinBiaoData.setUpdateOption();
        return newScore - oldScore;
    }

    /**
     * 能否购买战令
     */
    public boolean canRechargeToken(MallInfo mallInfo) {

        // 判断时间
        if (!WasheMgr.inRechargeTokenTime()) {
            return false;
        }

        WasheConfig washeConfig = WasheMgr.getWasheConfig();
        int seasonId = washeConfig.getSeasonId();

        // 拿数据
        WasheUserData userData = getWasheUserData();
        if (userData == null || userData.isGuide()) {
            return false;
        }

        // 拿战令
        Set<Integer> tokenSet;
        if (mallInfo.getShopType() == eShopType.ChineseChessSilverToken.getValue()) {
            tokenSet = userData.getSilverSet();
        } else if (mallInfo.getShopType() == eShopType.ChineseChessGoldToken.getValue()) {
            tokenSet = userData.getGoldSet();
        } else {
            return false;
        }

        // 是否重复购买
        if (tokenSet.contains(seasonId)) {
            return false;
        }

        return true;
    }

    /**
     * 购买战令
     */
    public void rechargeToken(MallInfo mallInfo) {
        // 拿赛季
        WasheConfig washeConfig = WasheMgr.getWasheConfig();
        if (washeConfig == null || washeConfig.getSeasonId() <= WasheConfig.SEASON_ID_TEST) {
            log.error("userId {} rechargeToken error! no washe season or season zero! mallId {} shopType {} category {}.",
                    getUserId(), mallInfo.getMallId(), mallInfo.getShopType(), mallInfo.getCategory());
            return;
        }
        int seasonId = washeConfig.getSeasonId();

        // 拿数据
        WasheUserData userData = getWasheUserData();
        if (userData == null) {
            log.error("userId {} rechargeToken error! no washe user data! mallId {} shopType {} category {}.",
                    getUserId(), mallInfo.getMallId(), mallInfo.getShopType(), mallInfo.getCategory());
            return;
        }

        // 拿战令
        Set<Integer> tokenSet;
        if (mallInfo.getShopType() == eShopType.ChineseChessSilverToken.getValue()) {
            tokenSet = userData.getSilverSet();
        } else if (mallInfo.getShopType() == eShopType.ChineseChessGoldToken.getValue()) {
            tokenSet = userData.getGoldSet();
        } else {
            log.error("userId {} rechargeToken error! no washe user data! mallId {} shopType {} category {}.",
                    getUserId(), mallInfo.getMallId(), mallInfo.getShopType(), mallInfo.getCategory());
            return;
        }

        // 是否重复购买
        if (tokenSet.contains(seasonId)) {
            log.error("userId {} rechargeToken error! repeated buy! mallId {} shopType {} category {} seasonId {}.",
                    getUserId(), mallInfo.getMallId(), mallInfo.getShopType(), mallInfo.getCategory(), seasonId);
            return;
        }

        // 购买成功
        tokenSet.add(seasonId);
        userData.setUpdateOption();

        // 同步购买状态
        syncUserData(washeConfig, userData, getWasheUserJinBiaoData());
    }

    /**
     * 购买一张卡片
     */
    private boolean buyOneCard(WasheConfig config, WasheCardConfig cardConfig) {
        long price = cardConfig.getPrice();
        if (price <= 0) {
            return false; // 无需购买 || 无法购买
        }

        Property cost = PropertyHelper.parseStringToProperty(config.getSanXiaoBiId() + "=" + price);
        Property reward = PropertyHelper.parseStringToProperty(cardConfig.getItemId() + "=1");

        // 扣消耗
        CurrencyModule currencyModule = player.getModule(CurrencyModule.class);
        if (!currencyModule.removeCurrency(cost, eLogMoneyType.Washe, eLogMoneyType.WashePlayOnMatchBuyCard)) {
            return false;
        }

        // 加奖励
        currencyModule.addCurrency(reward, eLogMoneyType.Washe, eLogMoneyType.WashePlayOnMatchBuyCard);

        return true;
    }

    /**
     * 触发现金礼包
     */
    public void triggerRmbMall(WasheLastResultData lastResultData) {

        WasheConfig config = WasheMgr.getWasheConfig();
        WasheUserData userData = getWasheUserData();
        if (config == null || userData == null) {
            return;
        }

        // 非新手且无赛季时无法触发
        if (!userData.isGuide() && !config.seasonInTime()) {
            return;
        }

        // 好友、练习模式无法触发
        boolean win;
        try {
            byte[] decode = Base64.getDecoder().decode(lastResultData.getMsgData());
            WasheProto.WasheGameOverMsg overMsg = WasheProto.WasheGameOverMsg.parseFrom(decode);
            if (overMsg.getRoomData().getModeId() == eWasheModeType.FriendPk.getValue() || overMsg.getRoomData().getModeId() == eWasheModeType.Practice.getValue()
                    || overMsg.getRoomData().getModeId() == eWasheModeType.AreaPk.getValue()) {
                return;
            }
            win = overMsg.getWin();
        } catch (Exception e) {
            log.error("error : ", e);
            return;
        }


        ConcurrentHashMap<Integer, WasheRmbMallData> rmbMallMap = userData.getRmbMallMap();
        Map<Integer, MallInfo> mallInfoMap = NormalActivityMgr.getMallInfoTypeMap(config.getActivityInfo().getActivityId(), eShopType.WasheRmbMall.getValue());
        for (MallInfo mallInfo : mallInfoMap.values()) {
            // 初始数据
            WasheRmbMallData mall = rmbMallMap.get(mallInfo.getMallId());
            if (mall == null) {
                mall = new WasheRmbMallData();
                mall.setMallId(mallInfo.getMallId());
                mall.setBeginTime(0);
                mall.setTimes(0);
                mall.setFailTimes(0);
                rmbMallMap.put(mall.getMallId(), mall);
            }
            // 检查CD、过期、重置
            if (mall.inCd(config.getRmbMallCdTime())) {
                continue;
            } else {
                if (mall.getBeginTime() > 0 && !mall.canBuy(config.getRmbMallTime())) {
                    mall.reset();
                }
            }
            // 修改连败次数
            if (win) {
                mall.setFailTimes(0);
                continue;
            } else {
                mall.setFailTimes(mall.getFailTimes() + 1);
            }
            // 检查触发
            List<Long> list = StringUtils.stringToLongList(mallInfo.getExtendParam(), "\\|");
            long minScore = list.get(0);
            long maxScore = list.get(1);
            long continueFailureTimes = list.get(2);
            if (mall.getFailTimes() >= continueFailureTimes &&
                    minScore <= userData.getScore() && userData.getScore() <= maxScore) {
                // 触发
                mall.setBeginTime(System.currentTimeMillis());
                mall.setTimes(1);
                // 日志
                AutoLogMgr.add(new LogWasheRmbMall(
                        getUserId(),
                        mallInfo.getMallId(),
                        true,
                        mall.getTimes()
                ));
            }
        }
        userData.setUpdateOption();
    }


    /**
     * 能不能购买直购方式的瓦舍现金礼包
     */
    public boolean canBuyDirectRmbMall(int mallId){
        WasheConfig config = WasheMgr.getWasheConfig();
        WasheUserData userData = getWasheUserData();
        if (userData == null) {
            return false;
        }
        ConcurrentHashMap<Integer, WasheRmbMallData> rmbMallMap = userData.getRmbMallMap();
        //拿出直购类型的瓦舍现金礼包
        Map<Integer, MallInfo> mallInfoTypeMap = NormalActivityMgr.getMallInfoTypeMap(config.getActivityInfo().getActivityId(), eShopType.WaSheDirectPurchaseRmbMall.getValue());
        long now = System.currentTimeMillis();
        for (MallInfo mallInfo : mallInfoTypeMap.values()) {
            //先遍历 初始化一下数据
            WasheRmbMallData mall = rmbMallMap.get(mallInfo.getMallId());
            if (mall == null) {
                mall = new WasheRmbMallData();
                mall.setMallId(mallInfo.getMallId());
                mall.setBeginTime(now);
                mall.setTimes(mallInfo.getLimitBuyCount());
                mall.setFailTimes(0);
                rmbMallMap.put(mall.getMallId(), mall);
                userData.setUpdateOption();
            } else {
                //每日重置一下
                if (!DateHelper.isSameDay(mall.getBeginTime()/1000,now/1000)){
                    mall.setBeginTime(now);
                    mall.setTimes(mallInfo.getLimitBuyCount());
                    mall.setFailTimes(0);
                    userData.setUpdateOption();
                }
            }
        }
        WasheRmbMallData washeRmbMallData = rmbMallMap.get(mallId);
        if (washeRmbMallData == null){
            return false;
        }
        //没买过 可以买
        if (washeRmbMallData.getTimes() > 0){
            return true;
        }else {
            return false;
        }
    }


    /**
     * 能不能买触发式现金礼包
     */
    public boolean canBuyRmbMall(int mallId) {
        WasheConfig config = WasheMgr.getWasheConfig();
        WasheUserData userData = getWasheUserData();
        if (config == null || userData == null) {
            return false;
        }

        WasheRmbMallData mall = userData.getRmbMallMap().get(mallId);
        if (mall == null) {
            return false;
        }
        if (!mall.canBuy(config.getRmbMallTime())) {
            return false;
        }
        return true;
    }

    /**
     * 扣次数
     */
    public void reduceRmbMallTimes(int mallId) {
        WasheUserData userData = getWasheUserData();
        if (userData != null) {
            WasheRmbMallData data = userData.getRmbMallMap().get(mallId);
            data.setTimes(Math.max(0, data.getTimes() - 1));
            userData.setUpdateOption();

            // 日志
            AutoLogMgr.add(new LogWasheRmbMall(
                    getUserId(),
                    data.getMallId(),
                    false,
                    data.getTimes()
            ));
        }
    }

    /**
     * 修改历史记录
     */
    public void changeHistory(Map<Integer, Long> typeValueMap) {

        WasheUserData userData = getWasheUserData();
        boolean guide = userData == null || userData.isGuide();

        // 非正式赛季不触发 || 新手阶段不触发
        int seasonId = WasheMgr.getWasheConfig().getSeasonId();
        if (seasonId <= WasheConfig.SEASON_ID_TEST || guide) {
            return;
        }

        Set<WasheHistoryTemp> checkHonorMomentSet = new HashSet<>();

        for (Map.Entry<Integer, Long> entry : typeValueMap.entrySet()) {
            int type = entry.getKey();
            long value = entry.getValue();

            // 【获取对象】
            WasheHistoryTemp historyTemp;
            if (type == eWasheHonorMomentType.Collect_OneGameUseCardTimes.getIntValue()) {
                historyTemp = history.getLastGameHistoryTempMap().get(type);
                if (historyTemp == null) {
                    historyTemp = new WasheHistoryTemp(type, 0);
                    history.getLastGameHistoryTempMap().put(historyTemp.getType(), historyTemp);
                }
            } else if (type == eWasheHonorMomentType.Collect_SeasonBattleTimes.getIntValue()) {
                history.getSeasonHistoryTempMap().putIfAbsent(seasonId, new ConcurrentHashMap<>());
                ConcurrentHashMap<Integer, WasheHistoryTemp> map = history.getSeasonHistoryTempMap().get(seasonId);
                historyTemp = map.get(type);
                if (historyTemp == null) {
                    historyTemp = new WasheHistoryTemp(type, 0);
                    map.put(historyTemp.getType(), historyTemp);
                }
            } else {
                historyTemp = history.getHistoryTempMap().get(type);
                if (historyTemp == null) {
                    historyTemp = new WasheHistoryTemp(type, 0);
                    history.getHistoryTempMap().put(historyTemp.getType(), historyTemp);
                }
            }

            // 【修改值】
            if (type == eWasheHonorMomentType.Collect_ConsecutiveWin.getIntValue()) { // 连胜次数，对局结束加1或重置，并检查是否超过历史最高
                historyTemp.setValue(value >= 0 ? historyTemp.getValue() + value : 0);
                if (historyTemp.getValue() > 0) {
                    WasheHistoryTemp temp2 = history.getHistoryTempMap().get(eWasheHonorMomentType.ConsecutiveWin.getIntValue());
                    if (temp2 == null) {
                        temp2 = new WasheHistoryTemp(eWasheHonorMomentType.ConsecutiveWin.getIntValue(), 0);
                        history.getHistoryTempMap().put(eWasheHonorMomentType.ConsecutiveWin.getIntValue(), temp2);
                    }
                    if (historyTemp.getValue() > temp2.getValue()) {
                        temp2.setValue(historyTemp.getValue());
                        checkHonorMomentSet.add(temp2);
                    }
                }

            } else if (type == eWasheHonorMomentType.ConsecutiveEliminate.getIntValue()
                    || type == eWasheHonorMomentType.HonorPoint.getIntValue()
                    || type == eWasheHonorMomentType.UnlockCardKind.getIntValue()
                    || type == eWasheHonorMomentType.OneGameUseCardTimes.getIntValue()
                    || type == eWasheHonorMomentType.OneGameScore.getIntValue()) { // 【取最高】
                if (value > historyTemp.getValue()) {
                    historyTemp.setValue(value);
                    checkHonorMomentSet.add(historyTemp);
                }

            } else if (type == eWasheHonorMomentType.EliminateBlueCount.getIntValue()
                    || type == eWasheHonorMomentType.EliminateRedCount.getIntValue()
                    || type == eWasheHonorMomentType.UseHammerTimes.getIntValue()
                    || type == eWasheHonorMomentType.LoseCardCount.getIntValue()
                    || type == eWasheHonorMomentType.GetCardCount.getIntValue()
                    || type == eWasheHonorMomentType.BattleTimes.getIntValue()
                    || type == eWasheHonorMomentType.SendExpressionTimes.getIntValue()
                    || type == eWasheHonorMomentType.SurrenderTimes.getIntValue()
                    || type == eWasheHonorMomentType.Collect_OneGameUseCardTimes.getIntValue()
                    || type == eWasheHonorMomentType.Collect_SeasonBattleTimes.getIntValue()) { // 【直接加】
                historyTemp.setValue(value + historyTemp.getValue());
                checkHonorMomentSet.add(historyTemp);

            }
        }

        // 设置状态
        history.setUpdateOption();

        // 检查荣誉瞬间
        checkHonorMoment(checkHonorMomentSet);
    }

    /**
     * 检查荣誉瞬间达成
     */
    private void checkHonorMoment(Set<WasheHistoryTemp> checkHonorMomentSet) {
        WasheConfig config = WasheMgr.getWasheConfig();
        if (config == null) {
            return;
        }

        Map<Integer, List<WasheHonorMomentConfig>> honorMomentConfigMap = config.getHonorMomentConfigMap();
        ConcurrentHashMap<Integer, WasheHonorMomentTemp> honorMomentTempMap = honorMoment.getHonorMomentTempMap();
        for (WasheHistoryTemp historyTemp : checkHonorMomentSet) {
            List<WasheHonorMomentConfig> configList = honorMomentConfigMap.get(historyTemp.getType());
            if (configList == null || configList.isEmpty()) {
                continue;
            }

            // 【找粗略的开始下标】
            int startIndex = 0;
            int blockSize = 10; // 每次找10个
            for (int blockIndex = 0; blockIndex < configList.size() / blockSize; blockIndex++) {
                WasheHonorMomentConfig tmpConfig = configList.get(blockIndex * blockSize);
                if (!honorMomentTempMap.containsKey(tmpConfig.getHonorMomentId())) {
                    startIndex = (blockIndex - 1) * blockSize;
                    break;
                } else {
                    startIndex = blockIndex * blockSize;
                }
            }
            startIndex = Math.max(0, startIndex);

            // 【从下标开始检查完成情况】
            List<WasheHonorMomentTemp> list = new ArrayList<>();
            for (int i = startIndex; i < configList.size(); i++) {
                WasheHonorMomentConfig tmpConfig = configList.get(i);
                // 已完成
                if (honorMomentTempMap.containsKey(tmpConfig.getHonorMomentId())) {
                    continue;
                }
                // 可以达成
                if (historyTemp.getValue() >= tmpConfig.getCondition()) {
                    WasheHonorMomentTemp honorMomentTemp = new WasheHonorMomentTemp(tmpConfig.getHonorMomentId(), System.currentTimeMillis());
                    honorMomentTempMap.put(tmpConfig.getHonorMomentId(), honorMomentTemp);
                    honorMoment.setUpdateOption();

                    list.add(honorMomentTemp);
                    continue;
                }
                // 无法达成
                break;
            }

            // 对刚达成的成就操作一下
            if (list.size() > 0) {
                if (historyTemp.getType() == eWasheHonorMomentType.UnlockCardKind.getIntValue()
                        || historyTemp.getType() == eWasheHonorMomentType.GetCardCount.getIntValue()) {
                    syncUnlockCardHonorMoment(list);
                } else {
                    honorMoment.getLastGameMomentTempList().addAll(list);
                    honorMoment.setUpdateOption();
                }
            }
        }
    }

    /**
     * 单独同步荣誉瞬间：解锁卡片
     */
    private void syncUnlockCardHonorMoment(List<WasheHonorMomentTemp> list) {
        WasheProto.WasheSyncHonorMomentRespMsg.Builder builder = WasheProto.WasheSyncHonorMomentRespMsg.newBuilder();
        for (WasheHonorMomentTemp honorMomentTemp : list) {
            builder.addHonorMoment(WashePb.parseWasheHonorMomentMsg(honorMomentTemp));
        }
        player.sendPacket(ClientProtocol.U_WASHE_SYNC_HONOR_MOMENT, builder);
    }

    public int buySkill(int skillId, int num) {
        WasheConfig config = WasheMgr.getWasheConfig();
        WasheUserData userData = getWasheUserData();

        // 配置
        WasheSkillConfig skillConfig = config.getSkillConfigMap().get(skillId);
        if (skillConfig == null) {
            return GameErrorCode.E_WASHE_SKILL_NO_EXIST;
        }
        Long price = skillConfig.getPriceMap().get(num);
        if (price == null) {
            return GameErrorCode.E_WASHE_PARAM_ERROR;
        }

        // 是否解锁
        if (!userData.getUnlockSkill().contains(skillId)) {
            return GameErrorCode.E_WASHE_SKILL_NO_UNLOCK;
        }

        Property cost = new Property();
        cost.addProperty(config.getSanXiaoBiId(), BigInteger.valueOf(price));
        Property reward = new Property();
        reward.addProperty(skillConfig.getItemId(), BigInteger.valueOf(num));

        // 扣消耗
        if (!player.getModule(CurrencyModule.class).removeCurrency(cost, eLogMoneyType.Washe, eLogMoneyType.WasheBuySkill)) {
            return GameErrorCode.E_BAG_ITEM_NO_ENOUGH;
        }
        // 加奖励
        player.getModule(CurrencyModule.class).addCurrency(reward, eLogMoneyType.Washe, eLogMoneyType.WasheBuySkill);

        // 返回
        WasheProto.WasheBuySkillRespMsg.Builder builder = WasheProto.WasheBuySkillRespMsg.newBuilder();
        builder.setRet(0);
        builder.setReward(PropertyHelper.parsePropertyToString(reward));
        player.sendPacket(ClientProtocol.U_WASHE_BUY_SKILL, builder);
        return 0;
    }

    // =================== 对局结果太多了放这边 =====================

    /**
     * 游戏结束修改buff
     */
    private void gameOverChangeBuff(WasheConfig config, WasheUserData userData, boolean win) {

        int buffTimes = userData.getBuffTimes();

        if (buffTimes >= 0) {

            // 有buff不能攒次数
            userData.setBuffCollectTimes(0);

            // buff有次数 || 持续连胜buff时输了，要扣次数
            if (buffTimes > 0 || !win) {
                userData.setBuffTimes(buffTimes - 1);
            }

        } else {

            // 没buff，赢了就可以攒次数
            if (win) {
                userData.setBuffCollectTimes(userData.getBuffCollectTimes() + 1);
            } else {
                userData.setBuffCollectTimes(0);
            }
            // 攒够了触发buff
            if (userData.getBuffCollectTimes() >= config.getBuffNeedWin()) {
                userData.setBuffCollectTimes(0);
                userData.setBuffTimes(config.getBuffTimes());
            }

        }
    }

    /**
     * 游戏结束加减分
     *
     * @return 真实变化分数（新手阶段无法超过新手最高分）
     */
    private long gameOverChangeScore(WasheConfig config, WasheUserData userData, boolean win, int tiredBuff, int winBuff) {
        WasheRankConfig rankConfig = config.getWasheRankConfig(userData.getScore(), userData.isGuide());
        // 获取基础分数
        long scoreChange = win ? rankConfig.getWinPoint() : rankConfig.getLosePoint() * -1;
        // buff加成
        scoreChange = BigDecimal.valueOf(scoreChange)
                .multiply(BigDecimal.valueOf(tiredBuff))
                .multiply(BigDecimal.valueOf(winBuff))
                .divide(BigDecimal.valueOf(1000), 0, BigDecimal.ROUND_UP)
                .divide(BigDecimal.valueOf(1000), 0, BigDecimal.ROUND_UP)
                .longValue();
        // 修改分数
        return changeScore(config, userData, scoreChange);
    }

    /**
     * 锦标赛积分变化
     */
    private long gameOverChangeJinBiaoScore(WasheConfig config, WasheUserJinBiaoData jinBiaoData, int modeId, boolean win, int winBuff) {
        long scoreChange = 0;
        if (modeId == eWasheModeType.JinBiaoScoreLow.getValue()) {
            scoreChange = win ? config.getJinBiaoLowWinRewardIntegral() : config.getJinBiaoLowLoseRewardIntegral();
        } else if (modeId == eWasheModeType.JinBiaoScoreHigh.getValue()) {
            scoreChange = win ? config.getJinBiaoHighWinRewardIntegral() : config.getJinBiaoHighLoseRewardIntegral();
        }
        // buff加成
        scoreChange = BigDecimal.valueOf(scoreChange)
                .multiply(BigDecimal.valueOf(winBuff))
                .divide(BigDecimal.valueOf(1000), 0, RoundingMode.UP)
                .longValue();
        // 积分赛积分变化
        return changeJinBiaoScore(config, jinBiaoData, scoreChange);
    }

    /**
     * 添加积分道具(投放)
     */
    public void addJinBiaoScore(BigInteger count) {
        WasheConfig washeConfig = WasheMgr.washeConfig;
        if (washeConfig == null) {
            log.warn("addJinBiaoScore error no washe config!!!!");
            return;
        }
        WasheUserJinBiaoData jinBiaoData = getWasheUserJinBiaoData();
        if (jinBiaoData == null) {
            log.warn("addJinBiaoScore error jinBiaoData is null!!!!");
            return;
        }
        // 加积分
        changeJinBiaoScore(washeConfig, jinBiaoData, count.longValue());
    }

    /**
     * 游戏结束掉落宝箱
     */
    public void gameOverGetBox(WasheConfig config, WasheUserData userData, boolean win, Property showReward, LogWasheGameOver logWasheGameOver, boolean firstWin) {
        if (!win) {
            return;
        }
        List<WasheBoxData> boxDataList = userData.getBoxDataList();
        if (boxDataList.size() >= config.getMaxBoxCount()) {
            return;
        }

        long score = userData.getScore();

        // 随机宝箱品质
        int index = RandomHelper.getRandomIndexByWeight(config.getBoxWeightList(), random);
        if (index > 2) {
            log.error("userId {} random box index {}", getUserId(), index);
            return;
        }
        int qua = new int[]{3, 2, 1}[index];

        // 计算开启时间
        long openCostTime = config.getBoxTimeList().get(index);

        // 获取可用宝箱
        List<WasheBoxConfig> boxConfigList = config.getWasheBoxConfigList(userData.getDataSeason());
        boxConfigList = boxConfigList.stream().filter(item ->
                item.getQuality() == qua && item.getScoreLimit().get(0) <= score && score <= item.getScoreLimit().get(1)
        ).collect(Collectors.toList());
        if (boxConfigList.size() == 0) {
            log.info("userId {} box qua {} score {}, no find box config", getUserId(), qua, score);
            return;
        }
        WasheBoxConfig boxConfig = boxConfigList.get(random.nextInt(boxConfigList.size()));

        // 新手引导宝箱
        boolean getNewHandBox = player.getModule(AttributeModule.class).getAttribute(ePlayerAttrType.WasheNewHandBox) == 1;
        if (!getNewHandBox && firstWin) {
            List<WasheBoxConfig> tmpList = config.getWasheBoxConfigList(-2);
            for (WasheBoxConfig tmp : tmpList) {
                boxConfig = tmp;
                openCostTime = DateHelper.SECOND_MILLIONS;
                break;
            }
        }
        if (!getNewHandBox) {
            player.getModule(AttributeModule.class).setAttribute(ePlayerAttrType.WasheNewHandBox, 1);
        }

        // 获取奖励
        String reward;
        if (!eWasheFunction.NewBoxConfig.isOpen(config.getVersion())) {
            int rewardIndex = RandomHelper.getRandomIndexByWeight(boxConfig.getWeightList(), random);
            reward = boxConfig.getRewardList().get(rewardIndex);
        } else {
            reward = PropertyHelper.parsePropertyToString(PropertyHelper.parseNewStringToProperty(boxConfig.getNewrewards()));
        }

        // 加奖励
        long getTime = System.currentTimeMillis();
        WasheBoxData boxData = new WasheBoxData(boxConfig.getSeasonId(), boxConfig.getBoxId(), getTime, getTime + openCostTime, reward);
        boxDataList.add(boxData);
        userData.setUpdateOption();

        // 展示的奖励
        showReward.addProperty(boxData.getBoxId(), BigInteger.ONE);

        // 日志
        logWasheGameOver.setGetBoxId(boxData.getBoxId());
        // 日志
        AutoLogMgr.add(new LogWasheBox(
                getUserId(),
                config.getSeasonId(),
                config.getWasheRankConfig(score, userData.isGuide()).getRankId(),
                boxData.getSeasonId(),
                boxData.getBoxId(),
                boxConfig.getQuality(),
                false,
                ""
        ));
    }

    /**
     * 游戏结束获得任务道具
     */
    private void gameOverGetTaskItem(WasheConfig config, WasheUserData userData, boolean win, Property showReward, LogWasheGameOver log, int gameOverType) {
        if (!win) {
            if (gameOverType == WasheGameOverType.SURRENDER || gameOverType == WasheGameOverType.DISCONNECT) { // 非正常失败不能拿奖励
                return;
            }
        }
        if (userData.getDataSeason() <= WasheConfig.SEASON_ID_NULL) {
            return;
        }
        WasheSeasonConfig seasonConfig = config.getWasheSeasonConfig();
        int taskItemId = seasonConfig.getTaskItemId();
        if (taskItemId == 0) {
            return;
        }

        int taskItemNum = win ? config.getWinGetTaskItemNum() : config.getFailGetTaskItemNum();
        player.notifySeasonReward(eSeasonRewardType.WasheTimeLimitTask, new WasheTimeLimitTaskArgs(taskItemId, taskItemNum));

        // 展示的奖励
        showReward.addProperty(taskItemId, BigInteger.valueOf(taskItemNum));

        // 日志
        log.setTaskItemId(taskItemId);
        log.setGetTaskItemNum(taskItemNum);
    }

    /**
     * 游戏结束获得三消币
     */
    private void gameOverGetSanXiaoBi(int modeId, WasheConfig config, boolean win, int tiredBuff, int winBuff, Property showReward,
                                      long selfScore, long opponentScore) {
        // 获取数量
        long getNum = 0;
        if (modeId == eWasheModeType.JinBiaoScoreLow.getValue()) {
            // 积分赛低级场
            getNum = win ? config.getJinBiaoLowWinRewardMoney() : config.getJinBiaoLowLoseRewardMoney();
        } else if (modeId == eWasheModeType.JinBiaoScoreHigh.getValue()) {
            // 积分赛高级场
            getNum = win ? config.getJinBiaoHighWinRewardMoney() : config.getJinBiaoHighLoseRewardMoney();
        } else {
            // 常规匹配
            if (win) {
                long div = opponentScore == 0 ? 0 : selfScore * 1000 / opponentScore;
                for (List<Integer> list : config.getWinGetSanXiaoBiList()) {
                    if (div >= list.get(0)) {
                        getNum = list.get(1);
                    }
                }
            } else {
                getNum = config.getFailGetSanXiaoBi();
            }
        }

        // 计算buff
        getNum = BigDecimal.valueOf(getNum)
                .multiply(BigDecimal.valueOf(tiredBuff))
                .multiply(BigDecimal.valueOf(winBuff))
                .divide(BigDecimal.valueOf(1000), 0, BigDecimal.ROUND_UP)
                .divide(BigDecimal.valueOf(1000), 0, BigDecimal.ROUND_UP)
                .longValue();

        // 加奖励
        if (getNum > 0) {
            Property sanXiaoBiProp = PropertyHelper.parseStringToProperty(config.getSanXiaoBiId() + "=" + getNum);
            player.getModule(CurrencyModule.class).addCurrency(sanXiaoBiProp, eLogMoneyType.Washe, eLogMoneyType.WashePlayResult);

            // 展示的奖励
            showReward.addProperty(config.getSanXiaoBiId(), BigInteger.valueOf(getNum));
        }
    }

    /**
     * 消耗卡片
     */
    private List<Integer> gameOverConsumeCard(WasheConfig config, boolean win, int useCardId, LogWasheGameOver logWasheGameOver) {

        // 不管输赢消耗保护卡
        boolean useSafeCard = false;
        Property safeCard = PropertyHelper.parseStringToProperty(config.getSafeCardId() + "=1");
        if (player.getModule(CurrencyModule.class).removeCurrency(safeCard, eLogMoneyType.Washe, eLogMoneyType.WashePlayResult)) {
            useSafeCard = true;
        }

        // 输了扣卡片（卡片不免费、无保护卡才扣）
        WasheCardConfig useCardConfig = config.getCardConfigMap().get(useCardId);
        if (!win && !useCardConfig.isFree() && !useSafeCard) {
            Property cardProp = PropertyHelper.parseStringToProperty(useCardConfig.getItemId() + "=1");
            if (!player.getModule(CurrencyModule.class).removeCurrency(cardProp, eLogMoneyType.Washe, eLogMoneyType.WashePlayResult)) {
                log.error("washe consume card fail! card no enough! userId {} cardId {}.", getUserId(), useCardConfig.getItemId());
            }
        }

        // 不考虑保护卡的情况下，应该扣的卡片
        int showCostCard = 0;
        if (!win && !useCardConfig.isFree()) {
            showCostCard = useCardId;
        }

        // 结果
        List<Integer> resultList = new ArrayList<>();
        resultList.add(showCostCard);
        resultList.add(useSafeCard ? 1 : 0);

        // 日志
        logWasheGameOver.setHasSafeCard(useSafeCard);

        return resultList;
    }

    private void gameOverConsumeSkill(WasheConfig config, boolean win, List<Integer> skillIdList) {

        // 2023年3月31日11:51 盘面技能，打赢了会扣数量吗
        // 2023年3月31日12:13 会扣

        Property property = new Property();
        Map<Integer, WasheSkillConfig> skillConfigMap = config.getSkillConfigMap();
        for (int skillId : skillIdList) {
            WasheSkillConfig skillConfig = skillConfigMap.get(skillId);
            if (skillConfig != null && !skillConfig.isFree()) {
                property.addProperty(skillConfig.getItemId(), BigInteger.ONE);
            }
        }
        if (property.isNothing()) {
            return;
        }

        // 扣消耗
        if (!player.getModule(CurrencyModule.class).removeCurrency(property, eLogMoneyType.Washe, eLogMoneyType.WashePlayResult)) {
            log.error("washe consume card fail! card no enough! userId {} cost {}.", getUserId(), PropertyHelper.parsePropertyToString(property));
        }
    }

    /**
     * 获取赛季回忆
     */
    private WasheProto.WasheSeasonMemoryMsg.Builder getWasheSeasonMemoryMsg(WasheConfig config, WasheUserData userData) {
        int seasonId = config.getSeasonId();
        if (seasonId < 2) {
            return null; // 从第二赛季开始才有赛季回忆
        }
        int oldSeason = seasonId - 1;

        // 获取赛季对战次数
        long seasonBattleTimes = 0;
        ConcurrentHashMap<Integer, WasheHistoryTemp> map = history.getSeasonHistoryTempMap().get(oldSeason);
        if (map != null) {
            WasheHistoryTemp historyTemp = map.get(eWasheHonorMomentType.Collect_SeasonBattleTimes.getIntValue());
            if (historyTemp != null) {
                seasonBattleTimes = historyTemp.getValue();
            }
        }
        if (seasonBattleTimes < config.getMemoryNeedBattleTimes()) {
            return null;
        }

        // 随机三个荣誉瞬间
        WasheSeasonConfig oldSeasonConfig = config.getSeasonConfigMap().get(oldSeason);
        List<WasheHonorMomentTemp> honorMomentTempList = honorMoment.getHonorMomentTempMap().values().stream().filter(item ->
                oldSeasonConfig.getBeginShowTime() <= item.getTime() && item.getTime() <= oldSeasonConfig.getEndShowTime()).collect(Collectors.toList());
        Collections.shuffle(honorMomentTempList);

        // 解锁的最高级的三张卡
        List<WasheCardConfig> unlockCardList = new ArrayList<>();
        Map<Integer, WasheCardConfig> cardConfigMap = config.getCardConfigMap();
        for (int cardId : userData.getUnlockCard()) {
            unlockCardList.add(cardConfigMap.get(cardId));
        }
        Collections.sort(unlockCardList, new Comparator<WasheCardConfig>() {
            @Override
            public int compare(WasheCardConfig o1, WasheCardConfig o2) {
                if (o1.getQuality() != o2.getQuality()) return Integer.compare(o2.getQuality(), o1.getQuality());
                return Integer.compare(o2.getCardId(), o1.getCardId());
            }
        });

        // 使用次数最多的卡
        int topCardId = 1;
        long topCardTimes = 0;
        for (Map.Entry<Integer, Long> entry : history.getCardUseTimesMap().entrySet()) {
            if (entry.getValue() > topCardTimes) {
                topCardId = entry.getKey();
                topCardTimes = entry.getValue();
            }
        }

        // 赛季最终荣誉点
        long seasonScore = userData.getSeasonScoreMap().getOrDefault(oldSeason, 0L);

        // 赛季最终排名
        int rank = WasheMgr.getHistoryRank(oldSeason, eSeasonRewardType.WasheScoreRank.getIntValue(), getUserId());

        // 赛季获得的序章
        List<Integer> badgeIdList = new ArrayList<>();
        List<UserBadge> badgeList = player.getModule(BadgeModule.class).getUserBadgeMap().getOrDefault(eBadgeType.Washe.getValue(), new ArrayList<>());
        for (UserBadge userBadge : badgeList) {
            BadgeConfig badgeConfig = BadgeConfigMgr.getBadgeConfig(userBadge.getBadgeType(), userBadge.getBadgeId());
            if (badgeConfig != null && badgeConfig.getSeasonParamList().size() >= 1 && badgeConfig.getSeasonParamList().get(0) == oldSeason) {
                badgeIdList.add(badgeConfig.getId());
            }
        }

        // 积分赛排名
        int jinBiaoScoreRank = WasheMgr.getHistoryRank(oldSeason, eSeasonRewardType.JinBiaoScoreRank.getIntValue(), getUserId());
        // 巅峰赛排名
        int jinBiaoPeakRank = WasheMgr.getHistoryRank(oldSeason, eSeasonRewardType.JinBiaoPeakRank.getIntValue(), getUserId());
        // 积分赛积分
        WasheUserJinBiaoData jinBiaoData = getWasheUserJinBiaoData();
        long jinBiaoScore = jinBiaoData.getScore();

        // 返回
        WasheProto.WasheSeasonMemoryMsg.Builder seasonMemoryBuilder = WasheProto.WasheSeasonMemoryMsg.newBuilder();
        seasonMemoryBuilder.setOldSeasonId(oldSeason);
        seasonMemoryBuilder.setSeasonBattleTimes(seasonBattleTimes);
        for (int i = 0; i < honorMomentTempList.size() && i < 3; i++) {
            seasonMemoryBuilder.addHonorMoment(WashePb.parseWasheHonorMomentMsg(honorMomentTempList.get(i)));
        }
        for (int i = 0; i < unlockCardList.size() && i < 3; i++) {
            seasonMemoryBuilder.addTopUnlockCardId(unlockCardList.get(i).getCardId());
        }
        seasonMemoryBuilder.setTopUseCardId(topCardId);
        seasonMemoryBuilder.setTopUseCardTimes(topCardTimes);
        seasonMemoryBuilder.setSeasonScore(seasonScore);
        seasonMemoryBuilder.setSeasonRank(rank);
        seasonMemoryBuilder.addAllSeasonBadge(badgeIdList);
        seasonMemoryBuilder.setJinBiaoScoreRank(jinBiaoScoreRank);
        seasonMemoryBuilder.setJinBiaoPeakRank(jinBiaoPeakRank);
        seasonMemoryBuilder.setJinBiaoScore(jinBiaoScore);
        return seasonMemoryBuilder;
    }

    private int getLogOpponentType(int modeId, long userId2) {
        if (modeId == eWasheModeType.Practice.getValue()) {
            return 4; // 4练习模式
        }
        if (modeId == eWasheModeType.FriendPk.getValue()) {
            return 3; // 3好友
        }
        if (modeId == eWasheModeType.JinBiaoScoreLow.getValue()) {
            return 5;   // 积分赛低级场
        }
        if (modeId == eWasheModeType.JinBiaoScoreHigh.getValue()) {
            return 6;   // 积分赛高级场
        }
        if (modeId == eWasheModeType.JinBiaoPeak.getValue()) {
            return 7;   // 巅峰赛
        }
        if (modeId == eWasheModeType.AreaPk.getValue()) {
            return 8;   // 地区pk
        }

        if (userId2 == 0) {
            return 1; // 1匹配AI
        }

        return 2; // 2匹配玩家
    }

    // ========================================
    /**
     * 匹配
     */
    public int matchAreaPk(int modeId, int cardId, List<Integer> skillIdList) {
        WasheConfig config = WasheMgr.getWasheConfig();
        WasheUserData userData = getWasheUserData();
        // 每日开放时间限制
        long now = System.currentTimeMillis();
        long dayTime = now - DateHelper.getTodayZeroTimeStamp();
        List<List<Long>> dayOpenTime = config.getDayOpenTime();
        boolean isOpen = false;
        for (List<Long> list : dayOpenTime) {
            if (list.get(0) < dayTime && dayTime < list.get(1)) {
                isOpen = true;
                break;
            }
        }
        if (!isOpen) {
            return GameErrorCode.E_WASHE_NO_IN_PLAY_TIME;
        }

        // 检测匹配限制
        VerificationModule verificationModule = player.getModule(VerificationModule.class);
        if (!verificationModule.canPlay(eSystemId.WasheActivity.getValue())) {
            // 推送下验证码
            verificationModule.verificationDatasync(eSystemId.WasheActivity.getValue());
            return GameErrorCode.E_WASHE_MATCH_LIMIT;
        }

        //地域赛，只有锤子
        if(modeId == eWasheModeType.AreaPk.getValue()){
            skillIdList = new ArrayList<>();
            skillIdList.add(1001);
            skillIdList.add(1002);
        }

        // 卡片判断
        WasheCardConfig cardConfig = config.getCardConfigMap().get(cardId);
        if (cardConfig == null) {
            return GameErrorCode.E_WASHE_CARD_NO_EXIST;
        }

        if(modeId == eWasheModeType.AreaPk.getValue()){
            //卡片品质控制
            AreaWashePkConfig pkConfig = AreaWasePkMgr.getConfig();
            if(pkConfig == null){
                return GameErrorCode.E_REQUEST_ARGUMENT_ERROR;
            }
            if(!pkConfig.getCartLvList().contains(cardConfig.getQuality())){
                return GameErrorCode.E_WASHE_CARD_NO_UNLOCK;
            }
        }

        // 发送到跨域
        WasheProto.ChannelWasheMatchReqMsg.Builder builder = createMatchBuilder(cardId, userData, false, null, modeId, skillIdList);
        player.sendChannelPacket(ChannelProtocol.N_WASHE_MATCH, builder);

        return 0;
    }

    /**
     * 匹配
     */
    public int match(int modeId, int cardId, List<Integer> skillIdList) {
        WasheConfig config = WasheMgr.getWasheConfig();
        WasheUserData userData = getWasheUserData();
        WasheUserJinBiaoData jinBiaoData = getWasheUserJinBiaoData();
        if (!userData.isGuide()) {
            boolean seasonInTime = config.seasonInTime();
            // 无赛季匹配限制
            if (!seasonInTime && !eWasheFunction.NoSeasonMatch.isOpen(config.getVersion())) {
                return GameErrorCode.E_WASHE_NO_IN_PLAY_TIME;
            }
            // 赛季继承限制
            if (seasonInTime && userData.getDataSeason() != config.getSeasonId()) {
                return GameErrorCode.E_WASHE_NEED_CHANGE_SEASON;
            }
            boolean isJinBiaoScore = modeId == eWasheModeType.JinBiaoScoreLow.getValue() || modeId == eWasheModeType.JinBiaoScoreHigh.getValue();
            // 锦标赛积分赛是否开启
            if (isJinBiaoScore) {
                if (!config.getWasheSeasonConfig().isJiFenOpen() || !config.jinBiaoScoreInTime()) {
                    return GameErrorCode.E_WASHE_NO_IN_PLAY_TIME;
                }
                // 获取体力消耗
                int costEnergy = 1;
                if (modeId == eWasheModeType.JinBiaoScoreLow.getValue()) {
                    costEnergy = config.getJinBiaoScoreLowCost();
                } else if (modeId == eWasheModeType.JinBiaoScoreHigh.getValue()) {
                    costEnergy = config.getJinBiaoScoreHighCost();
                }
                if (jinBiaoData.getEnergy() < costEnergy) {
                    return GameErrorCode.E_WASHE_JINBIAO_ENERGY_NOT_ENOUGH;
                }
            }
            // 每日开放时间限制
            long now = System.currentTimeMillis();
            long dayTime = now - DateHelper.getTodayZeroTimeStamp();
            List<List<Long>> dayOpenTime = isJinBiaoScore ? config.getJinBiaoScoreDayOpenTime() : config.getDayOpenTime();
            boolean isOpen = false;
            for (List<Long> list : dayOpenTime) {
                if (list.get(0) < dayTime && dayTime < list.get(1)) {
                    isOpen = true;
                    break;
                }
            }
            if (!isOpen) {
                return GameErrorCode.E_WASHE_NO_IN_PLAY_TIME;
            }
        } else {
            // 已经可以脱离新手了，但是没有脱离新手
            if (userData.getScore() >= config.getNewHandScore()) {
                return GameErrorCode.E_WASHE_SHOULD_GET_REWARD;
            }
        }

        // 检测匹配限制
        VerificationModule verificationModule = player.getModule(VerificationModule.class);
        if (!verificationModule.canPlay(eSystemId.WasheActivity.getValue())) {
            // 推送下验证码
            verificationModule.verificationDatasync(eSystemId.WasheActivity.getValue());
            return GameErrorCode.E_WASHE_MATCH_LIMIT;
        }

        // 盘面技能判断
        Map<Integer, WasheSkillConfig> skillConfigMap = config.getSkillConfigMap();
        Set<Integer> unlockSkill = userData.getUnlockSkill();
        for (int skillId : skillIdList) {
            WasheSkillConfig skillConfig = skillConfigMap.get(skillId);
            if (skillConfig == null) {
                return GameErrorCode.E_WASHE_SKILL_NO_EXIST;
            }
            if (!unlockSkill.contains(skillId)) {
                return GameErrorCode.E_WASHE_SKILL_NO_UNLOCK;
            }
            if (!skillConfig.isFree()) {
                if (!player.getModule(CurrencyModule.class).currencyIsEnough(PropertyHelper.parseStringToProperty(skillConfig.getItemId() + "=1"))) {
                    return GameErrorCode.E_WASHE_SKILL_NO_ENOUGH;
                }
            }
        }

        // 卡片判断
        WasheCardConfig cardConfig = config.getCardConfigMap().get(cardId);
        if (cardConfig == null) {
            return GameErrorCode.E_WASHE_CARD_NO_EXIST;
        }
        if (!userData.getUnlockCard().contains(cardId)) {
            return GameErrorCode.E_WASHE_CARD_NO_UNLOCK;
        }
        if (!cardConfig.isFree()) {
            if (!player.getModule(CurrencyModule.class).currencyIsEnough(PropertyHelper.parseStringToProperty(cardConfig.getItemId() + "=1"))) {
                // 卡片不够，尝试购买
                if (!buyOneCard(config, cardConfig)) {
                    return GameErrorCode.E_WASHE_CARD_NO_ENOUGH;
                }
            }
        }
        // 积分赛判断卡片品质
        if (modeId == eWasheModeType.JinBiaoScoreLow.getValue()) {
            // 低级场  锦标赛-低级场条件：玩家卡牌品质小于等于
            if (cardConfig.getQuality() > config.getJinBiaoLowCondition()) {
                return GameErrorCode.E_WASHE_JIN_BIAO_CARD_LIMIT;
            }
        } else if (modeId == eWasheModeType.JinBiaoScoreHigh.getValue()) {
            // 高级场  锦标赛-高级场条件：玩家卡牌品质大于等于
            if (cardConfig.getQuality() < config.getJinBiaoHighCondition()) {
                return GameErrorCode.E_WASHE_JIN_BIAO_CARD_LIMIT;
            }
        }

        // 发送到跨域
        WasheProto.ChannelWasheMatchReqMsg.Builder builder = createMatchBuilder(cardId, userData, false, null, modeId, skillIdList);
        player.sendChannelPacket(ChannelProtocol.N_WASHE_MATCH, builder);

        // 保存选择的盘面技能
        userData.setSelectedSkill(skillIdList);

        return 0;
    }

    /**
     * 匹配
     */
    public int matchPractice(int modeId, int cardId, int sceneId, List<Integer> skillIdList) {
        WasheConfig config = WasheMgr.getWasheConfig();
        WasheUserData userData = getWasheUserData();

        // 盘面机制判断
        WasheSceneConfig sceneConfig = config.getSceneConfigMap().get(sceneId);
        if (sceneConfig == null || !sceneConfig.isOpen() || eWasheSceneType.getEnumByType(sceneId) == null) {
            return GameErrorCode.E_WASHE_SCENE_NO_EXIST;
        }

        // 卡片判断
        WasheCardConfig cardConfig = config.getCardConfigMap().get(cardId);
        if (cardConfig == null) {
            return GameErrorCode.E_WASHE_CARD_NO_EXIST;
        }
        if (!userData.getUnlockCard().contains(cardId)) {
            return GameErrorCode.E_WASHE_CARD_NO_UNLOCK;
        }

        // 盘面技能判断
        Map<Integer, WasheSkillConfig> skillConfigMap = config.getSkillConfigMap();
        Set<Integer> unlockSkill = userData.getUnlockSkill();
        for (int skillId : skillIdList) {
            WasheSkillConfig skillConfig = skillConfigMap.get(skillId);
            if (skillConfig == null) {
                return GameErrorCode.E_WASHE_SKILL_NO_EXIST;
            }
            if (!unlockSkill.contains(skillId)) {
                return GameErrorCode.E_WASHE_SKILL_NO_UNLOCK;
            }
        }

        // 发送到跨域
        WasheProto.ChannelWasheMatchReqMsg.Builder builder = createMatchBuilder(cardId, userData, true, sceneId, modeId, skillIdList);
        player.sendChannelPacket(ChannelProtocol.N_WASHE_MATCH, builder);
        return 0;
    }


    /**
     * 取消匹配
     */
    public int cancelMatch() {
        // 发送到跨域
        WasheProto.ChannelWasheCancelMatchReqMsg.Builder builder = WasheProto.ChannelWasheCancelMatchReqMsg.newBuilder();
        builder.setUserKey(WashePb2.parseChannelWasheUserKeyMsg(WasheMgr.getUserKey(getUserId())));
        player.sendChannelPacket(ChannelProtocol.N_WASHE_CANCEL_MATCH, builder);
        return 0;
    }

    /**
     * 请求房间数据
     */
    public int getRoomDataByCmd() {
        // 发送到跨域
        WasheProto.ChannelWasheGetRoomDataReqMsg.Builder builder = WasheProto.ChannelWasheGetRoomDataReqMsg.newBuilder();
        builder.setUserKey(WashePb2.parseChannelWasheUserKeyMsg(WasheMgr.getUserKey(getUserId())));
        player.sendChannelPacket(ChannelProtocol.N_WASHE_GET_ROOM_DATA, builder);
        return 0;
    }

    /**
     * 投降
     */
    public int surrender() {
        WasheConfig config = WasheMgr.getWasheConfig();
        WasheUserData userData = getWasheUserData();

        // 发送到跨域
        WasheProto.ChannelWasheSurrenderReqMsg.Builder builder = WasheProto.ChannelWasheSurrenderReqMsg.newBuilder();
        builder.setUserKey(WashePb2.parseChannelWasheUserKeyMsg(WasheMgr.getUserKey(getUserId())));
        builder.setTimesLimit(userData.getDaySurrenderTimes() >= config.getDaySurrenderTimes());
        player.sendChannelPacket(ChannelProtocol.N_WASHE_SURRENDER, builder);
        return 0;
    }

    /**
     * 请求玩家数据
     */
    public int getUserDataByCmd(boolean getGameOver) {
        WasheConfig config = WasheMgr.getWasheConfig();
        WasheUserData userData = getWasheUserData();

        WasheProto.WasheGameOverMsg gameOverMsg = null;
        if (getGameOver) {
            WasheLastResultData tmp = WasheMgr.getLastResultData(userData.getUserId());
            if (tmp != null && !tmp.isRead() && !StringUtils.isNullOrEmpty(tmp.getMsgData())) {
                try {
                    byte[] decode = Base64.getDecoder().decode(tmp.getMsgData());
                    gameOverMsg = WasheProto.WasheGameOverMsg.parseFrom(decode);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }

        WasheProto.WasheGetUserRespMsg.Builder builder = WasheProto.WasheGetUserRespMsg.newBuilder();
        builder.setRet(0);
        builder.setUserData(WashePb.parseWasheUserDataMsg(config, userData, getWasheUserJinBiaoData(), gameOverMsg));
        player.sendPacket(ClientProtocol.U_WASHE_GET_USER_DATA, builder);
        return 0;
    }

    /**
     * 游戏内操作
     */
    public int operate(WasheProto.WasheOperateReqMsg reqMsg) {

        if (reqMsg.getType() == eWasheOperateType.SendExpression.getValue()) {
            // 校验表情
            int expressionId = reqMsg.getExpressionId();
            ExpressionInfo expressionInfo = ChatConfigMgr.getExpressionByNum(expressionId);
            if (expressionInfo == null) {
                return GameErrorCode.E_MESSAGE_EXPRESSION_NO_FOUND;
            }
            if (!expressionInfo.isFree() && !player.getModule(BagModule.class).hasEnoughGoods(expressionInfo.getItemId(), 1)) {
                return GameErrorCode.E_MESSAGE_EXPRESSION_LOCK;
            }
        }

        // 发送到跨域
        WasheProto.ChannelWasheOperateReqMsg.Builder builder = WasheProto.ChannelWasheOperateReqMsg.newBuilder();
        builder.setUserKey(WashePb2.parseChannelWasheUserKeyMsg(WasheMgr.getUserKey(getUserId())));
        builder.setReq(reqMsg.toBuilder());
        player.sendChannelPacket(ChannelProtocol.N_WASHE_OPERATE, builder);
        return 0;
    }

    /**
     * 游戏结束操作
     */
    public WasheProto.WasheGameOverMsg.Builder gameOverAction(WasheProto.WasheGameOverMsg gameOverMsg) {

        // 匹配类型
        int modeId = gameOverMsg.getRoomData().getModeId();
        WasheConfig config = WasheMgr.getWasheConfig();

        if (modeId == eWasheModeType.FriendPk.getValue()
                || modeId == eWasheModeType.Practice.getValue()) {
            // 好友对战 || 练习模式
            return gameOverActionFriend(gameOverMsg);
        } else if (modeId == eWasheModeType.JinBiaoScoreLow.getValue() || modeId == eWasheModeType.JinBiaoScoreHigh.getValue()) {
            // 积分赛
            return gameOverActionScore(gameOverMsg);
        } else if (modeId == eWasheModeType.JinBiaoPeak.getValue()) {
            // 巅峰赛
            return gameOverActionPeak(gameOverMsg);
        } else if (modeId == eWasheModeType.AreaPk.getValue()){
            // 地区pk
            return gameOverAreaPk(gameOverMsg);
        }


        WasheUserData userData = getWasheUserData();

        // 日志
        LogWasheGameOver logWasheGameOver = new LogWasheGameOver();

        // 返回值里拿点数据
        WasheProto.WasheRoomDataMsg roomDataMsg = gameOverMsg.getRoomData();
        WasheProto.WasheUserGameDataMsg selfGameData = roomDataMsg.getSelfData();
        WasheProto.WasheUserGameDataMsg opponentGameData = roomDataMsg.getOpponentData();
        WasheProto.WasheOpponentMsg opponent = roomDataMsg.getOpponent();
        boolean win = gameOverMsg.getWin();
        int useCardId = selfGameData.getCard().getCardId();
        long costTime = gameOverMsg.getCostTime();
        int logOldRankId = config.getWasheRankConfig(userData.getScore(), userData.isGuide()).getRankId();
        List<Integer> skillIdList = selfGameData.getSkillList().stream().mapToInt(item -> item.getSkillId()).boxed().collect(Collectors.toList());

        boolean firstWin = userData.getScore() == 0 && win;
        boolean isSurrender = !win && gameOverMsg.getEndType() == WasheGameOverType.SURRENDER;
        boolean seasonInTime = config.seasonInTime();

        boolean hasSurrenderLimit = eWasheFunction.DaySurrenderLimit.isOpen(config.getVersion());
        boolean hasTiredBuff = eWasheFunction.TiredBuff.isOpen(config.getVersion()) && !userData.isGuide() && seasonInTime;
        boolean hasContinueWinBuff = eWasheFunction.ContinueWinBuff.isOpen(config.getVersion()) && (userData.isGuide() || seasonInTime);
        boolean onlySanXiaoBiReward = !userData.isGuide() && !seasonInTime;

        // 修改对局次数
        userData.setPlayTimes(userData.getPlayTimes() + 1);
        if (hasSurrenderLimit) {
            userData.setDaySurrenderTimes(userData.getDaySurrenderTimes() + (isSurrender ? 1 : 0));
        }
        if (hasTiredBuff) {
            userData.setDayPlayTimes(userData.getDayPlayTimes() + 1);
        }
        if (hasContinueWinBuff) {
            userData.setContinueWinTimes(!win ? 0 : userData.getContinueWinTimes() + 1);
        }

        // 修改对局时间
        userData.setSeasonPlayTime(userData.getSeasonPlayTime() + costTime);
        userData.setTodayPlayTime(userData.getTodayPlayTime() + costTime);

        // 存奖励结果
        Property showReward = new Property();

        // 【计算buff】
        int winBuff = 1000;
        int tiredBuff = 1000;
        if (!onlySanXiaoBiReward) {
            // 1. 胜利buff
            if (hasContinueWinBuff) {
                if (win) {
                    winBuff = config.getWinAddition(userData.getContinueWinTimes());
                }
            } else {
                if (win && userData.getBuffTimes() >= 0) {
                    winBuff = 2000;
                }
                gameOverChangeBuff(config, userData, win);
            }
            // 2. 疲劳buff
            if (hasTiredBuff) {
                if (win) {
                    tiredBuff = config.getTiredByTimes(userData.getDayPlayTimes());
                }
            }
        }

        // 获得荣誉点
        long scoreChange = 0;
        if (!onlySanXiaoBiReward) {
            scoreChange = gameOverChangeScore(config, userData, win, tiredBuff, winBuff);
        }

        // 宝箱相关
        if (!onlySanXiaoBiReward) {
            gameOverGetBox(config, userData, win, showReward, logWasheGameOver, firstWin);
        }

        // 任务道具相关
        if (!onlySanXiaoBiReward) {
            gameOverGetTaskItem(config, userData, win, showReward, logWasheGameOver, gameOverMsg.getEndType());
        }

        // 三消币
        gameOverGetSanXiaoBi(modeId, config, win, tiredBuff, winBuff, showReward, selfGameData.getScore(), opponentGameData.getScore());

        // 消耗卡片
        List<Integer> consumeCardResult = gameOverConsumeCard(config, win, useCardId, logWasheGameOver);

        // 消耗技能
        gameOverConsumeSkill(config, win, skillIdList);

        // 记录卡片使用次数
        Map<Integer, Long> cardUseTimesMap = history.getCardUseTimesMap();
        cardUseTimesMap.put(useCardId, 1 + cardUseTimesMap.getOrDefault(useCardId, 0L));
        history.setUpdateOption();

        // 对局记录
        if (!userData.isGuide() && userData.getDataSeason() > WasheConfig.SEASON_ID_TEST) {
            WasheBattleRecord record = new WasheBattleRecord();
            record.setUserId(getUserId());
            record.setNo(maxRecordId.incrementAndGet());
            record.setTime(System.currentTimeMillis());
            record.setOpponentInfo(WashePb.parseWasheBattleRecordOpponent(opponent));
            record.setOpponentCardId(opponentGameData.getCard().getCardId());
            record.setOpponentScore(opponentGameData.getScore());
            record.setSelfCardId(selfGameData.getCard().getCardId());
            record.setSelfScore(selfGameData.getScore());
            record.setWin(win);
            record.setScoreChange(scoreChange);
            record.setType(0);
            record.setSelfSkills(selfGameData.getSkillList().stream().map(item -> item.getSkillId()).collect(Collectors.toList()));
            record.setOpponentSkills(opponentGameData.getSkillList().stream().map(item -> item.getSkillId()).collect(Collectors.toList()));
            record.setJinBiaoScoreChange(0);
            record.setInsertOption();
            recordListMap.get(record.getType()).add(record);
            for (List<WasheBattleRecord> recordList : recordListMap.values()) {
                if (recordList.size() > config.getMaxRecordNum()) {
                    recordList.remove(0); // 不判断是否保存，不可能一次性添加上限条数的记录
                }
            }
        }

        // 直播来搞一下
        if (win) {
            player.getModule(DailyDataModule.class).notifyLiveShowWashe();
        }

        // 【日志】
        logWasheGameOver.setUserId(getUserId());
        logWasheGameOver.setCardId(selfGameData.getCard().getCardId());
        logWasheGameOver.setUserId2(opponent.getUserId());
        logWasheGameOver.setCardId2(opponentGameData.getCard().getCardId());
        logWasheGameOver.setRoomId(roomDataMsg.getRoomId());
        logWasheGameOver.setSceneId(roomDataMsg.getSceneId());
        logWasheGameOver.setSeasonId(config.getSeasonId());
        logWasheGameOver.setRankId(logOldRankId);
        logWasheGameOver.setWin(win);
        logWasheGameOver.setGameOverType(gameOverMsg.getEndType());
        logWasheGameOver.setChangeHonor(scoreChange);
        logWasheGameOver.setNewHonor(userData.getScore());
        // logWasheGameOver.setTaskItemId();
        // logWasheGameOver.setGetTaskItemNum();
        // logWasheGameOver.setHasSafeCard();
        // logWasheGameOver.setGetBoxId();
        logWasheGameOver.setCostTime(costTime);
        logWasheGameOver.setGameScore(selfGameData.getScore());
        if (gameOverMsg.hasLogOpponentRankId()) {
            logWasheGameOver.setRankId2(gameOverMsg.getLogOpponentRankId());
        }
        logWasheGameOver.setEndRound(roomDataMsg.getRound());
        logWasheGameOver.setTodayPlayTime(userData.getTodayPlayTime());
        logWasheGameOver.setMatchCostTime(gameOverMsg.getLogMatchCostTime());
        logWasheGameOver.setTodayOnlineTime(player.getModule(SignModule.class).getTodayOnlineTime());
        logWasheGameOver.setOpponentType(getLogOpponentType(roomDataMsg.getModeId(), opponent.getUserId()));
        logWasheGameOver.setFirstOperate(!gameOverMsg.hasLogFirstOperate() ? 0 : gameOverMsg.getLogFirstOperate() ? 1 : 2);
        logWasheGameOver.setSkillList(JSON.toJSONString(selfGameData.getSkillList().stream().mapToInt(item -> item.getSkillId()).boxed().collect(Collectors.toList())));
        logWasheGameOver.setChangeJinBiaoScore(0);
        WasheUserJinBiaoData jinBiaoData = getWasheUserJinBiaoData();
        logWasheGameOver.setNewJinBiaoScore(jinBiaoData != null ? jinBiaoData.getScore() : 0);
        AutoLogMgr.add(logWasheGameOver);

        // 历史记录
        Map<Integer, Long> typeValueMap = new HashMap<>();
        typeValueMap.put(eWasheHonorMomentType.Collect_ConsecutiveWin.getIntValue(), win ? 1L : -1L);
        if (consumeCardResult.get(0) > 0 && consumeCardResult.get(1) == 0) {
            typeValueMap.put(eWasheHonorMomentType.LoseCardCount.getIntValue(), 1L);
        }
        typeValueMap.put(eWasheHonorMomentType.BattleTimes.getIntValue(), 1L);
        typeValueMap.put(eWasheHonorMomentType.Collect_SeasonBattleTimes.getIntValue(), 1L);
        WasheHistoryTemp oneGameUseCardTimes = history.getLastGameHistoryTempMap().get(eWasheHonorMomentType.Collect_OneGameUseCardTimes.getIntValue());
        if (oneGameUseCardTimes != null) {
            typeValueMap.put(eWasheHonorMomentType.OneGameUseCardTimes.getIntValue(), oneGameUseCardTimes.getValue());
        }
        if (!win && gameOverMsg.getEndType() == WasheGameOverType.SURRENDER) {
            typeValueMap.put(eWasheHonorMomentType.SurrenderTimes.getIntValue(), 1L);
        }
        typeValueMap.put(eWasheHonorMomentType.OneGameScore.getIntValue(), selfGameData.getScore());
        changeHistory(typeValueMap);

        // 修改完荣誉瞬间，要记录本局触发的荣誉瞬间
        List<WasheHonorMomentTemp> honorMomentTempList = new ArrayList<>(honorMoment.getLastGameMomentTempList());

        // 清空用过的数据
        history.getLastGameHistoryTempMap().clear();
        history.setUpdateOption();
        honorMoment.getLastGameMomentTempList().clear();
        honorMoment.setUpdateOption();

        // 加幸运签次数
        if (win && !onlySanXiaoBiReward) {
            player.getModule(LuckyDrawModule.class).addWasheWinTimes();
        }

        // 完成任务
        notifyWashePlayTimes(1);

        // 人机验证计数下
        player.getModule(VerificationModule.class).addConditionCount(eSystemId.WasheActivity.getValue(), eWasheVerificationConditionType.GameCount.getValue(), 1);

        // 返回
        WasheProto.WasheGameOverMsg.Builder builder = gameOverMsg.toBuilder();
        builder.setScoreChange(scoreChange);
        builder.setReward(PropertyHelper.parsePropertyToString(showReward));
        builder.setCostCardId(consumeCardResult.get(0));
        builder.setMultiBuff(!hasContinueWinBuff ? (winBuff / 1000) : 1); // 这个值是倍数，不是千分比，新版配置下固定传1，不使用这个参数
        builder.setUseSafeCard(consumeCardResult.get(1) != 0);
        for (WasheHonorMomentTemp temp : honorMomentTempList) {
            builder.addHonorMoment(WashePb.parseWasheHonorMomentMsg(temp));
        }
        builder.setTodayPlayTimes(hasTiredBuff ? userData.getDayPlayTimes() : 0);
        builder.setWinTimes(hasContinueWinBuff ? userData.getContinueWinTimes() : 0);
        return builder;
    }

    /**
     * 游戏结束操作（好友对战）
     */
    public WasheProto.WasheGameOverMsg.Builder gameOverActionFriend(WasheProto.WasheGameOverMsg gameOverMsg) {
        WasheConfig config = WasheMgr.getWasheConfig();
        WasheUserData userData = getWasheUserData();

        // 日志
        LogWasheGameOver logWasheGameOver = new LogWasheGameOver();

        // 返回值里拿点数据
        WasheProto.WasheRoomDataMsg roomDataMsg = gameOverMsg.getRoomData();
        WasheProto.WasheUserGameDataMsg selfGameData = roomDataMsg.getSelfData();
        WasheProto.WasheUserGameDataMsg opponentGameData = roomDataMsg.getOpponentData();
        WasheProto.WasheOpponentMsg opponent = roomDataMsg.getOpponent();
        boolean win = gameOverMsg.getWin();
        long costTime = gameOverMsg.getCostTime();
        int logOldRankId = config.getWasheRankConfig(userData.getScore(), userData.isGuide()).getRankId();

        // 【日志】
        logWasheGameOver.setUserId(getUserId());
        logWasheGameOver.setCardId(selfGameData.getCard().getCardId());
        logWasheGameOver.setUserId2(opponent.getUserId());
        logWasheGameOver.setCardId2(opponentGameData.getCard().getCardId());
        logWasheGameOver.setRoomId(roomDataMsg.getRoomId());
        logWasheGameOver.setSceneId(roomDataMsg.getSceneId());
        logWasheGameOver.setSeasonId(config.getSeasonId());
        logWasheGameOver.setRankId(logOldRankId);
        logWasheGameOver.setWin(win);
        logWasheGameOver.setGameOverType(gameOverMsg.getEndType());
        // logWasheGameOver.setChangeHonor(0);
        logWasheGameOver.setNewHonor(userData.getScore());
        // logWasheGameOver.setTaskItemId();
        // logWasheGameOver.setGetTaskItemNum();
        // logWasheGameOver.setHasSafeCard();
        // logWasheGameOver.setGetBoxId();
        logWasheGameOver.setCostTime(costTime);
        logWasheGameOver.setGameScore(selfGameData.getScore());
        if (gameOverMsg.hasLogOpponentRankId()) {
            logWasheGameOver.setRankId2(gameOverMsg.getLogOpponentRankId());
        }
        logWasheGameOver.setEndRound(roomDataMsg.getRound());
        logWasheGameOver.setTodayPlayTime(userData.getTodayPlayTime());
        // logWasheGameOver.setMatchCostTime(0);
        logWasheGameOver.setTodayOnlineTime(player.getModule(SignModule.class).getTodayOnlineTime());
        logWasheGameOver.setOpponentType(getLogOpponentType(roomDataMsg.getModeId(), opponent.getUserId()));
        logWasheGameOver.setFirstOperate(!gameOverMsg.hasLogFirstOperate() ? 0 : gameOverMsg.getLogFirstOperate() ? 1 : 2);
        logWasheGameOver.setSkillList(JSON.toJSONString(selfGameData.getSkillList().stream().mapToInt(item -> item.getSkillId()).boxed().collect(Collectors.toList())));
        logWasheGameOver.setChangeJinBiaoScore(0);
        WasheUserJinBiaoData jinBiaoData = getWasheUserJinBiaoData();
        logWasheGameOver.setNewJinBiaoScore(jinBiaoData != null ? jinBiaoData.getScore() : 0);
        AutoLogMgr.add(logWasheGameOver);

        // 返回
        WasheProto.WasheGameOverMsg.Builder builder = gameOverMsg.toBuilder();
        builder.setScoreChange(0);
        builder.setReward("");
        builder.setCostCardId(0);
        builder.setMultiBuff(1);
        builder.setUseSafeCard(false);
        builder.setTodayPlayTimes(0);
        builder.setWinTimes(0);
        return builder;
    }

    /**
     * 游戏结束操作（积分赛）
     */
    public WasheProto.WasheGameOverMsg.Builder gameOverActionScore(WasheProto.WasheGameOverMsg gameOverMsg) {
        // 匹配类型
        int modeId = gameOverMsg.getRoomData().getModeId();
        WasheConfig config = WasheMgr.getWasheConfig();
        WasheUserData userData = getWasheUserData();
        WasheUserJinBiaoData jinBiaoData = getWasheUserJinBiaoData();

        // 日志
        LogWasheGameOver logWasheGameOver = new LogWasheGameOver();

        // 返回值里拿点数据
        WasheProto.WasheRoomDataMsg roomDataMsg = gameOverMsg.getRoomData();
        WasheProto.WasheUserGameDataMsg selfGameData = roomDataMsg.getSelfData();
        WasheProto.WasheUserGameDataMsg opponentGameData = roomDataMsg.getOpponentData();
        WasheProto.WasheOpponentMsg opponent = roomDataMsg.getOpponent();
        boolean win = gameOverMsg.getWin();
        int useCardId = selfGameData.getCard().getCardId();
        long costTime = gameOverMsg.getCostTime();
        int logOldRankId = config.getWasheRankConfig(userData.getScore(), userData.isGuide()).getRankId();
        List<Integer> skillIdList = selfGameData.getSkillList().stream().mapToInt(item -> item.getSkillId()).boxed().collect(Collectors.toList());

        boolean isSurrender = !win && gameOverMsg.getEndType() == WasheGameOverType.SURRENDER;
        boolean seasonInTime = config.seasonInTime();

        boolean hasSurrenderLimit = eWasheFunction.DaySurrenderLimit.isOpen(config.getVersion());
        // 锦标赛积分赛连胜buff
        boolean hasContinueJinBiaoWinBuff = eWasheFunction.JinBiaoContinueWinBuff.isOpen(config.getVersion()) && seasonInTime;

        // 修改对局次数
        userData.setPlayTimes(userData.getPlayTimes() + 1);
        if (hasSurrenderLimit) {
            userData.setDaySurrenderTimes(userData.getDaySurrenderTimes() + (isSurrender ? 1 : 0));
        }
        if (hasContinueJinBiaoWinBuff) {
            jinBiaoData.setContinueWinTimes(!win ? 0 : jinBiaoData.getContinueWinTimes() + 1);
        }

        // 修改对局时间
        userData.setSeasonPlayTime(userData.getSeasonPlayTime() + costTime);
        userData.setTodayPlayTime(userData.getTodayPlayTime() + costTime);

        // 存奖励结果
        Property showReward = new Property();

        // 【计算buff】
        int winBuff = 1000;
        if (hasContinueJinBiaoWinBuff) {
            if (win) {
                winBuff = config.getJinBiaoScoreWinAddition(jinBiaoData.getContinueWinTimes());
            }
        }

        // 获得荣誉点
        long scoreChange = gameOverChangeScore(config, userData, win, 1000, winBuff);

        // 任务道具相关
        gameOverGetTaskItem(config, userData, win, showReward, logWasheGameOver, gameOverMsg.getEndType());

        // 积分赛对局奖励
        Property jinBiaoScoreReward = config.getJinBiaoScoreReward(modeId, win);
        player.getModule(CurrencyModule.class).addCurrency(jinBiaoScoreReward, eLogMoneyType.Washe, eLogMoneyType.WashePlayResult);
        showReward.addProperty(jinBiaoScoreReward);
        // 积分
        long jinBiaoScoreChange = gameOverChangeJinBiaoScore(config, jinBiaoData, modeId, win, winBuff);
        // 三消币
        gameOverGetSanXiaoBi(modeId, config, win, 1000, winBuff, showReward, selfGameData.getScore(), opponentGameData.getScore());

        // 消耗卡片
        List<Integer> consumeCardResult = gameOverConsumeCard(config, win, useCardId, logWasheGameOver);

        // 消耗技能
        gameOverConsumeSkill(config, win, skillIdList);

        // 记录卡片使用次数
        Map<Integer, Long> cardUseTimesMap = history.getCardUseTimesMap();
        cardUseTimesMap.put(useCardId, 1 + cardUseTimesMap.getOrDefault(useCardId, 0L));
        history.setUpdateOption();

        // 对局记录
        if (!userData.isGuide() && userData.getDataSeason() > WasheConfig.SEASON_ID_TEST) {
            WasheBattleRecord record = new WasheBattleRecord();
            record.setUserId(getUserId());
            record.setNo(maxRecordId.incrementAndGet());
            record.setTime(System.currentTimeMillis());
            record.setOpponentInfo(WashePb.parseWasheBattleRecordOpponent(opponent));
            record.setOpponentCardId(opponentGameData.getCard().getCardId());
            record.setOpponentScore(opponentGameData.getScore());
            record.setSelfCardId(selfGameData.getCard().getCardId());
            record.setSelfScore(selfGameData.getScore());
            record.setWin(win);
            record.setScoreChange(scoreChange);
            record.setType(1);
            record.setSelfSkills(selfGameData.getSkillList().stream().map(item -> item.getSkillId()).collect(Collectors.toList()));
            record.setOpponentSkills(opponentGameData.getSkillList().stream().map(item -> item.getSkillId()).collect(Collectors.toList()));
            record.setJinBiaoScoreChange(jinBiaoScoreChange);
            record.setInsertOption();
            recordListMap.get(record.getType()).add(record);
            for (List<WasheBattleRecord> recordList : recordListMap.values()) {
                if (recordList.size() > config.getMaxRecordNum()) {
                    recordList.remove(0); // 不判断是否保存，不可能一次性添加上限条数的记录
                }
            }
        }

        // 直播来搞一下
        if (win) {
            player.getModule(DailyDataModule.class).notifyLiveShowWashe();
        }

        // 【日志】
        logWasheGameOver.setUserId(getUserId());
        logWasheGameOver.setCardId(selfGameData.getCard().getCardId());
        logWasheGameOver.setUserId2(opponent.getUserId());
        logWasheGameOver.setCardId2(opponentGameData.getCard().getCardId());
        logWasheGameOver.setRoomId(roomDataMsg.getRoomId());
        logWasheGameOver.setSceneId(roomDataMsg.getSceneId());
        logWasheGameOver.setSeasonId(config.getSeasonId());
        logWasheGameOver.setRankId(logOldRankId);
        logWasheGameOver.setWin(win);
        logWasheGameOver.setGameOverType(gameOverMsg.getEndType());
        logWasheGameOver.setChangeHonor(scoreChange);
        logWasheGameOver.setNewHonor(userData.getScore());
        // logWasheGameOver.setTaskItemId();
        // logWasheGameOver.setGetTaskItemNum();
        // logWasheGameOver.setHasSafeCard();
        // logWasheGameOver.setGetBoxId();
        logWasheGameOver.setCostTime(costTime);
        logWasheGameOver.setGameScore(selfGameData.getScore());
        if (gameOverMsg.hasLogOpponentRankId()) {
            logWasheGameOver.setRankId2(gameOverMsg.getLogOpponentRankId());
        }
        logWasheGameOver.setEndRound(roomDataMsg.getRound());
        logWasheGameOver.setTodayPlayTime(userData.getTodayPlayTime());
        logWasheGameOver.setMatchCostTime(gameOverMsg.getLogMatchCostTime());
        logWasheGameOver.setTodayOnlineTime(player.getModule(SignModule.class).getTodayOnlineTime());
        logWasheGameOver.setOpponentType(getLogOpponentType(roomDataMsg.getModeId(), opponent.getUserId()));
        logWasheGameOver.setFirstOperate(!gameOverMsg.hasLogFirstOperate() ? 0 : gameOverMsg.getLogFirstOperate() ? 1 : 2);
        logWasheGameOver.setSkillList(JSON.toJSONString(selfGameData.getSkillList().stream().mapToInt(item -> item.getSkillId()).boxed().collect(Collectors.toList())));
        logWasheGameOver.setChangeJinBiaoScore(jinBiaoScoreChange);
        logWasheGameOver.setNewJinBiaoScore(jinBiaoData.getScore());
        AutoLogMgr.add(logWasheGameOver);

        // 历史记录
        Map<Integer, Long> typeValueMap = new HashMap<>();
        typeValueMap.put(eWasheHonorMomentType.Collect_ConsecutiveWin.getIntValue(), win ? 1L : -1L);
        if (consumeCardResult.get(0) > 0 && consumeCardResult.get(1) == 0) {
            typeValueMap.put(eWasheHonorMomentType.LoseCardCount.getIntValue(), 1L);
        }
        typeValueMap.put(eWasheHonorMomentType.BattleTimes.getIntValue(), 1L);
        typeValueMap.put(eWasheHonorMomentType.Collect_SeasonBattleTimes.getIntValue(), 1L);
        WasheHistoryTemp oneGameUseCardTimes = history.getLastGameHistoryTempMap().get(eWasheHonorMomentType.Collect_OneGameUseCardTimes.getIntValue());
        if (oneGameUseCardTimes != null) {
            typeValueMap.put(eWasheHonorMomentType.OneGameUseCardTimes.getIntValue(), oneGameUseCardTimes.getValue());
        }
        if (!win && gameOverMsg.getEndType() == WasheGameOverType.SURRENDER) {
            typeValueMap.put(eWasheHonorMomentType.SurrenderTimes.getIntValue(), 1L);
        }
        typeValueMap.put(eWasheHonorMomentType.OneGameScore.getIntValue(), selfGameData.getScore());
        changeHistory(typeValueMap);

        // 修改完荣誉瞬间，要记录本局触发的荣誉瞬间
        List<WasheHonorMomentTemp> honorMomentTempList = new ArrayList<>(honorMoment.getLastGameMomentTempList());

        // 清空用过的数据
        history.getLastGameHistoryTempMap().clear();
        history.setUpdateOption();
        honorMoment.getLastGameMomentTempList().clear();
        honorMoment.setUpdateOption();

        // 加幸运签次数
        if (win) {
            player.getModule(LuckyDrawModule.class).addWasheWinTimes();
        }

        // 完成任务
        notifyWashePlayTimes(1);

        // 返回
        WasheProto.WasheGameOverMsg.Builder builder = gameOverMsg.toBuilder();
        builder.setScoreChange(scoreChange);
        builder.setReward(PropertyHelper.parsePropertyToString(showReward));
        builder.setCostCardId(consumeCardResult.get(0));
        builder.setUseSafeCard(consumeCardResult.get(1) != 0);
        for (WasheHonorMomentTemp temp : honorMomentTempList) {
            builder.addHonorMoment(WashePb.parseWasheHonorMomentMsg(temp));
        }
        builder.setJinBiaoScoreChange(jinBiaoScoreChange);
        builder.setJinBiaoWinTimes(hasContinueJinBiaoWinBuff ? jinBiaoData.getContinueWinTimes() : 0);
        return builder;
    }


    /**
     * 游戏结束操作（巅峰赛）
     */
    public WasheProto.WasheGameOverMsg.Builder gameOverActionPeak(WasheProto.WasheGameOverMsg gameOverMsg) {
        WasheConfig config = WasheMgr.getWasheConfig();
        WasheUserData userData = getWasheUserData();
        WasheUserJinBiaoData jinBiaoData = getWasheUserJinBiaoData();
        // 匹配类型
        int modeId = gameOverMsg.getRoomData().getModeId();

        // 日志
        LogWasheGameOver logWasheGameOver = new LogWasheGameOver();

        // 返回值里拿点数据
        WasheProto.WasheRoomDataMsg roomDataMsg = gameOverMsg.getRoomData();
        WasheProto.WasheUserGameDataMsg selfGameData = roomDataMsg.getSelfData();
        WasheProto.WasheUserGameDataMsg opponentGameData = roomDataMsg.getOpponentData();
        WasheProto.WasheOpponentMsg opponent = roomDataMsg.getOpponent();
        boolean win = gameOverMsg.getWin();
        int useCardId = selfGameData.getCard().getCardId();
        long costTime = gameOverMsg.getCostTime();
        int logOldRankId = config.getWasheRankConfig(userData.getScore(), userData.isGuide()).getRankId();
        List<Integer> skillIdList = selfGameData.getSkillList().stream().mapToInt(item -> item.getSkillId()).boxed().collect(Collectors.toList());

        // 1:获胜 2:失败  3:平局
        if (gameOverMsg.getBattleResult() == 1) {
            // 记录胜利次数
            jinBiaoData.setPeakWinTimes(jinBiaoData.getPeakWinTimes() + 1);
        }
        // 记录积分
        if (selfGameData.getRobot()) {
            jinBiaoData.setPeakScore(jinBiaoData.getPeakScore() + selfGameData.getRobotScore());
        } else {
            jinBiaoData.setPeakScore(jinBiaoData.getPeakScore() + selfGameData.getScore());
        }

        // 上榜
        // 成就、榜单
        if (jinBiaoData.getDataSeason() == WasheConfig.SEASON_ID_NULL || jinBiaoData.getDataSeason() == config.getSeasonId()) {
            player.notifySeasonReward(eSeasonRewardType.JinBiaoPeakRank, new WasheJinBiaoPeakRankArgs(jinBiaoData.getPeakWinTimes(), jinBiaoData.getPeakScore()));
        }

        // 消耗卡片
        List<Integer> consumeCardResult = gameOverConsumeCard(config, win, useCardId, logWasheGameOver);

        // 消耗技能
        gameOverConsumeSkill(config, win, skillIdList);

        // 记录卡片使用次数
        Map<Integer, Long> cardUseTimesMap = history.getCardUseTimesMap();
        cardUseTimesMap.put(useCardId, 1 + cardUseTimesMap.getOrDefault(useCardId, 0L));
        history.setUpdateOption();

        // 获得荣誉点（巅峰赛不获得）
        long scoreChange = 0;

        // 存奖励结果
        Property showReward = new Property();
        // 巅峰赛对局奖励
        Property jinBiaoScoreReward = config.getJinBiaoScoreReward(modeId, win);
        player.getModule(CurrencyModule.class).addCurrency(jinBiaoScoreReward, eLogMoneyType.Washe, eLogMoneyType.WashePlayResult);
        showReward.addProperty(jinBiaoScoreReward);

        // 【日志】
        logWasheGameOver.setUserId(getUserId());
        logWasheGameOver.setCardId(selfGameData.getCard().getCardId());
        logWasheGameOver.setUserId2(opponent.getUserId());
        logWasheGameOver.setCardId2(opponentGameData.getCard().getCardId());
        logWasheGameOver.setRoomId(roomDataMsg.getRoomId());
        logWasheGameOver.setSceneId(roomDataMsg.getSceneId());
        logWasheGameOver.setSeasonId(config.getSeasonId());
        logWasheGameOver.setRankId(logOldRankId);
        logWasheGameOver.setWin(win);
        logWasheGameOver.setGameOverType(gameOverMsg.getEndType());
        logWasheGameOver.setChangeHonor(scoreChange);
        logWasheGameOver.setNewHonor(userData.getScore());
        // logWasheGameOver.setTaskItemId();
        // logWasheGameOver.setGetTaskItemNum();
        // logWasheGameOver.setHasSafeCard();
        // logWasheGameOver.setGetBoxId();
        logWasheGameOver.setCostTime(costTime);
        logWasheGameOver.setGameScore(selfGameData.getScore());
        if (gameOverMsg.hasLogOpponentRankId()) {
            logWasheGameOver.setRankId2(gameOverMsg.getLogOpponentRankId());
        }
        logWasheGameOver.setEndRound(roomDataMsg.getRound());
        logWasheGameOver.setTodayPlayTime(userData.getTodayPlayTime());
        logWasheGameOver.setMatchCostTime(gameOverMsg.getLogMatchCostTime());
        logWasheGameOver.setTodayOnlineTime(player.getModule(SignModule.class).getTodayOnlineTime());
        logWasheGameOver.setOpponentType(getLogOpponentType(roomDataMsg.getModeId(), opponent.getUserId()));
        logWasheGameOver.setFirstOperate(!gameOverMsg.hasLogFirstOperate() ? 0 : gameOverMsg.getLogFirstOperate() ? 1 : 2);
        logWasheGameOver.setSkillList(JSON.toJSONString(selfGameData.getSkillList().stream().mapToInt(item -> item.getSkillId()).boxed().collect(Collectors.toList())));
        logWasheGameOver.setChangeJinBiaoScore(0);
        logWasheGameOver.setNewJinBiaoScore(jinBiaoData.getScore());
        AutoLogMgr.add(logWasheGameOver);


        // 历史记录
        Map<Integer, Long> typeValueMap = new HashMap<>();
        typeValueMap.put(eWasheHonorMomentType.Collect_ConsecutiveWin.getIntValue(), win ? 1L : -1L);
        if (consumeCardResult.get(0) > 0 && consumeCardResult.get(1) == 0) {
            typeValueMap.put(eWasheHonorMomentType.LoseCardCount.getIntValue(), 1L);
        }
        typeValueMap.put(eWasheHonorMomentType.BattleTimes.getIntValue(), 1L);
        typeValueMap.put(eWasheHonorMomentType.Collect_SeasonBattleTimes.getIntValue(), 1L);
        WasheHistoryTemp oneGameUseCardTimes = history.getLastGameHistoryTempMap().get(eWasheHonorMomentType.Collect_OneGameUseCardTimes.getIntValue());
        if (oneGameUseCardTimes != null) {
            typeValueMap.put(eWasheHonorMomentType.OneGameUseCardTimes.getIntValue(), oneGameUseCardTimes.getValue());
        }
        if (!win && gameOverMsg.getEndType() == WasheGameOverType.SURRENDER) {
            typeValueMap.put(eWasheHonorMomentType.SurrenderTimes.getIntValue(), 1L);
        }
        typeValueMap.put(eWasheHonorMomentType.OneGameScore.getIntValue(), selfGameData.getScore());
        changeHistory(typeValueMap);

        // 修改完荣誉瞬间，要记录本局触发的荣誉瞬间
        List<WasheHonorMomentTemp> honorMomentTempList = new ArrayList<>(honorMoment.getLastGameMomentTempList());

        // 清空用过的数据
        history.getLastGameHistoryTempMap().clear();
        history.setUpdateOption();
        honorMoment.getLastGameMomentTempList().clear();
        honorMoment.setUpdateOption();

        // 加幸运签次数
        if (win) {
            player.getModule(LuckyDrawModule.class).addWasheWinTimes();
        }

        // 完成任务
        notifyWashePlayTimes(1);

        // 返回
        WasheProto.WasheGameOverMsg.Builder builder = gameOverMsg.toBuilder();
        builder.setCostCardId(consumeCardResult.get(0));
        builder.setUseSafeCard(consumeCardResult.get(1) != 0);
        for (WasheHonorMomentTemp temp : honorMomentTempList) {
            builder.addHonorMoment(WashePb.parseWasheHonorMomentMsg(temp));
        }
        builder.setPeakWinTimes(jinBiaoData.getPeakWinTimes());
        builder.setPeakScore(jinBiaoData.getPeakScore());
        builder.setReward(PropertyHelper.parsePropertyToString(showReward));
        return builder;
    }

    public WasheProto.WasheGameOverMsg.Builder gameOverAreaPk(WasheProto.WasheGameOverMsg gameOverMsg) {

        //加日志
        // 【日志】
        LogWasheGameOver logWasheGameOver = new LogWasheGameOver();


        WasheProto.WasheRoomDataMsg roomDataMsg = gameOverMsg.getRoomData();
        WasheProto.WasheUserGameDataMsg selfGameData = roomDataMsg.getSelfData();
        WasheProto.WasheUserGameDataMsg opponentGameData = roomDataMsg.getOpponentData();
        WasheProto.WasheOpponentMsg opponent = roomDataMsg.getOpponent();
        boolean win = gameOverMsg.getWin();
        //int useCardId = selfGameData.getCard().getCardId();
        long costTime = gameOverMsg.getCostTime();

        //List<Integer> skillIdList = selfGameData.getSkillList().stream().mapToInt(item -> item.getSkillId()).boxed().collect(Collectors.toList());

        logWasheGameOver.setUserId(getUserId());
        logWasheGameOver.setCardId(selfGameData.getCard().getCardId());
        logWasheGameOver.setUserId2(opponent.getUserId());
        logWasheGameOver.setCardId2(opponentGameData.getCard().getCardId());
        logWasheGameOver.setRoomId(roomDataMsg.getRoomId());
        logWasheGameOver.setSceneId(roomDataMsg.getSceneId());
        logWasheGameOver.setSeasonId(0);
        logWasheGameOver.setRankId(0);
        logWasheGameOver.setWin(win);
        logWasheGameOver.setGameOverType(gameOverMsg.getEndType());
        logWasheGameOver.setChangeHonor(gameOverMsg.getScoreChange());
        logWasheGameOver.setNewHonor(0);
        // logWasheGameOver.setTaskItemId();
        // logWasheGameOver.setGetTaskItemNum();
        // logWasheGameOver.setHasSafeCard();
        // logWasheGameOver.setGetBoxId();
        logWasheGameOver.setCostTime(costTime);
        logWasheGameOver.setGameScore(selfGameData.getScore());
        if (gameOverMsg.hasLogOpponentRankId()) {
            logWasheGameOver.setRankId2(gameOverMsg.getLogOpponentRankId());
        }
        logWasheGameOver.setEndRound(roomDataMsg.getRound());
        //
        logWasheGameOver.setTodayPlayTime(0);
        logWasheGameOver.setMatchCostTime(gameOverMsg.getLogMatchCostTime());
        logWasheGameOver.setTodayOnlineTime(player.getModule(SignModule.class).getTodayOnlineTime());
        logWasheGameOver.setOpponentType(getLogOpponentType(roomDataMsg.getModeId(), opponent.getUserId()));
        logWasheGameOver.setFirstOperate(!gameOverMsg.hasLogFirstOperate() ? 0 : gameOverMsg.getLogFirstOperate() ? 1 : 2);
        logWasheGameOver.setSkillList(JSON.toJSONString(selfGameData.getSkillList().stream().mapToInt(item -> item.getSkillId()).boxed().collect(Collectors.toList())));
        logWasheGameOver.setChangeJinBiaoScore(0);
        logWasheGameOver.setNewJinBiaoScore(0);

        if(gameOverMsg.hasActivityId()){
            logWasheGameOver.setActivityId(gameOverMsg.getActivityId());
        }
        if(gameOverMsg.hasZoneId()){
            logWasheGameOver.setZoneId(gameOverMsg.getZoneId());
        }
        if(gameOverMsg.hasZoneId2()){
            logWasheGameOver.setOpponentZoneId(gameOverMsg.getZoneId2());
        }
        AutoLogMgr.add(logWasheGameOver);

      return gameOverMsg.toBuilder();
    }

    /**
     * 客户端动画表现完成
     */
    public void clientShowFinish(WasheProto.WasheShowFinishReqMsg reqMsg) {
        // 发送到跨域
        WasheProto.ChannelWasheShowFinishReqMsg.Builder builder = WasheProto.ChannelWasheShowFinishReqMsg.newBuilder();
        builder.setUserKey(WashePb2.parseChannelWasheUserKeyMsg(WasheMgr.getUserKey(getUserId())));
        builder.setReq(reqMsg.toBuilder());
        player.sendChannelPacket(ChannelProtocol.N_WASHE_SHOW_FINISH, builder);
    }

    /**
     * 获取正在进行的游戏
     */
    public int getPlayingGameByCmd() {
        // 发送到跨域
        WasheProto.ChannelWasheGetPlayingGameReqMsg.Builder builder = WasheProto.ChannelWasheGetPlayingGameReqMsg.newBuilder();
        builder.setUserKey(WashePb2.parseChannelWasheUserKeyMsg(WasheMgr.getUserKey(getUserId())));
        player.sendChannelPacket(ChannelProtocol.N_WASHE_GET_PLAYING_GAME, builder);
        return 0;
    }

    /**
     * 脱离新手阶段
     */
    public int quitGuideByCmd(int type) {
        WasheConfig config = WasheMgr.getWasheConfig();
        if (config == null) {
            return GameErrorCode.E_WASHE_NO_SYSTEM;
        }
        WasheUserData userData = getWasheUserData();
        if (type == 1) {
            if (!userData.isGuide()) {
                return GameErrorCode.E_WASHE_NO_IN_GUIDE;
            }

            if (userData.getScore() < config.getNewHandScore()) {
                return GameErrorCode.E_WASHE_HONOR_NO_ENOUGH;
            }

            userData.setGuide(false);
            checkSeasonChange();
        } else if (type == 2) {
            userData.setLinkGuide(true);
        }
        WasheProto.WasheQuitGuideRespMsg.Builder builder = WasheProto.WasheQuitGuideRespMsg.newBuilder();
        builder.setRet(0);
        builder.setUserData(WashePb.parseWasheUserDataMsg(config, userData, getWasheUserJinBiaoData(), null));
        player.sendPacket(ClientProtocol.U_WASHE_QUIT_GUIDE, builder);
        return 0;
    }

    /**
     * 开启宝箱
     */
    public int openBoxByCmd(int index) {
        WasheConfig config = WasheMgr.getWasheConfig();
        WasheUserData userData = getWasheUserData();

        List<WasheBoxData> boxDataList = userData.getBoxDataList();
        if (index >= boxDataList.size()) {
            return GameErrorCode.E_WASHE_BOX_NO_EXIST;
        }

        WasheBoxData boxData = boxDataList.get(index);
        if (System.currentTimeMillis() < boxData.getCanOpenTime()) {
            return GameErrorCode.E_WASHE_BOX_BEFORE_OPEN_TIME;
        }

        // 拿奖励
        String reward = boxData.getReward();
        if (StringUtils.isNullOrEmpty(reward)) {
            return GameErrorCode.E_WASHE_BOX_NO_EXIST;
        }
        Property property = PropertyHelper.parseStringToProperty(reward);

        // 改状态
        boxDataList.remove(index);
        userData.setUpdateOption();

        // 加奖励
        player.getModule(CurrencyModule.class).addCurrency(property, eLogMoneyType.Washe, eLogMoneyType.WashePlayOpenBox);

        WasheProto.WasheOpenBoxRespMsg.Builder builder = WasheProto.WasheOpenBoxRespMsg.newBuilder();
        builder.setRet(0);
        builder.setReward(reward);
        builder.setUserData(WashePb.parseWasheUserDataMsg(config, userData, getWasheUserJinBiaoData(), null));
        player.sendPacket(ClientProtocol.U_WASHE_OPEN_BOX, builder);

        // 日志
        AutoLogMgr.add(new LogWasheBox(
                getUserId(),
                config.getSeasonId(),
                config.getWasheRankConfig(userData.getScore(), userData.isGuide()).getRankId(),
                boxData.getSeasonId(),
                boxData.getBoxId(),
                0,
                true,
                reward
        ));

        return 0;
    }

    /**
     * 获取对战记录
     */
    public List<WasheBattleRecord> getRecordListByCmd() {
        WasheConfig config = WasheMgr.getWasheConfig();
        WasheSeasonConfig seasonConfig = config.getWasheSeasonConfig();
        if (seasonConfig == null) {
            return new ArrayList<>();
        }

        List<WasheBattleRecord> list = new ArrayList<>();
        ConcurrentHashMap<Integer, List<WasheBattleRecord>> allMap = new ConcurrentHashMap<>(recordListMap);
        for (Map.Entry<Integer, List<WasheBattleRecord>> entry : allMap.entrySet()) {
            int recordType = entry.getKey();
            List<WasheBattleRecord> recordList = entry.getValue();
            for (int i = recordList.size() - 1; i >= 0; i--) {
                WasheBattleRecord record = recordList.get(i);
                if (seasonConfig.getBeginShowTime() <= record.getTime() && record.getTime() <= seasonConfig.getEndShowTime()) {
                    // 积分赛类型,过滤掉不在积分赛的时间内的记录
                    if (recordType == eWasheRecordType.JinBiaoScore.getValue() && (seasonConfig.getBeginShowTime() > record.getTime() || record.getTime() > seasonConfig.getEndShowTime())) {
                        break;
                    }
                    list.add(record);
                } else {
                    break;
                }
            }
        }

        Collections.reverse(list);
        return list;
    }

    /**
     * 获取勋章墙
     */
    public int getBadgeByCmd() {
        WasheUserData userData = getWasheUserData();
        WasheUserJinBiaoData jinBiaoData = getWasheUserJinBiaoData();
        List<UserBadge> badgeList = player.getModule(BadgeModule.class).getUserBadgeMap().getOrDefault(eBadgeType.Washe.getValue(), new ArrayList<>());

        WasheTmpBadgeResult result = WasheMgr.refreshWasheTmpBadgeResult(getUserId(), badgeList, userData, jinBiaoData);
        WasheTmpBadge cur = result.getCur();
        WasheTmpBadge top = result.getTop();
        List<WasheTmpBadge> list = result.getList();

        // 返回值
        WasheProto.WasheGetBadgeRespMsg.Builder builder = WasheProto.WasheGetBadgeRespMsg.newBuilder();
        builder.setRet(0);
        if (cur != null) {
            builder.setCur(WashePb.parseWasheBadgeMsg(cur));
        }
        if (top != null) {
            builder.setTop(WashePb.parseWasheBadgeMsg(top));
        }
        for (WasheTmpBadge tmpBadge : list) {
            builder.addList1(WashePb.parseWasheBadgeMsg(tmpBadge));
        }
        for (WasheHonorMomentTemp honorMomentTemp : honorMoment.getHonorMomentTempMap().values()) {
            builder.addList2(WashePb.parseWasheHonorMomentMsg(honorMomentTemp));
        }
        player.sendPacket(ClientProtocol.U_WASHE_GET_BADGE, builder);
        return 0;
    }

    /**
     * 获取赛季0过渡动画状态
     */
    public boolean getSeason0ShowByCmd() {
        WasheUserData userData = getWasheUserData();
        if (userData == null || userData.getDataSeason() != 0) {
            return false;
        }

        long attribute = player.getModule(AttributeModule.class).getAttribute(ePlayerAttrType.WasheSeason0Show);
        boolean needShow = attribute == 0;

        if (attribute == 0) {
            player.getModule(AttributeModule.class).setAttribute(ePlayerAttrType.WasheSeason0Show, 1);
        }

        return needShow;
    }

    /**
     * 赛季继承
     */
    public int seasonChangeByCmd() {
        WasheConfig config = WasheMgr.getWasheConfig();
        WasheUserData userData = getWasheUserData();

        // 【赛季继承】

        long oldScore = userData.getScore();

        boolean seasonChange = checkSeasonChange();
        if (!seasonChange) {
            return GameErrorCode.E_WASHE_SEASON_CAN_NOT_CHANGE;
        }

        long newScore = userData.getScore();
        WasheRankConfig rankConfig = config.getWasheRankConfig(newScore, userData.isGuide());
        int medal = rankConfig.getMedal();

        WasheProto.WasheSeasonChangeMsg.Builder seasonChangeBuilder = WasheProto.WasheSeasonChangeMsg.newBuilder();
        seasonChangeBuilder.setOldScore(oldScore);
        seasonChangeBuilder.setNewScore(newScore);
        if (medal > 0) {
            seasonChangeBuilder.setNewBadge(medal);
        }

        // 返回
        WasheProto.WasheSeasonChangeRespMsg.Builder builder = WasheProto.WasheSeasonChangeRespMsg.newBuilder();
        builder.setRet(0);
        builder.setSeasonChange(seasonChangeBuilder);
        player.sendPacket(ClientProtocol.U_WASHE_SEASON_CHANGE, builder);
        return 0;
    }

    /**
     * 赛季回忆
     */
    public int seasonMemoryByCmd() {
        WasheConfig config = WasheMgr.getWasheConfig();
        WasheUserData userData = getWasheUserData();

        List<Integer> seeList = userData.getMemorySeeList();

        WasheProto.WasheSeasonMemoryMsg.Builder seasonMemoryBuilder = null;
        int seasonId = config.getSeasonId();
        if (!seeList.contains(seasonId)) {
            seasonMemoryBuilder = getWasheSeasonMemoryMsg(config, userData);
            seeList.add(seasonId);
            userData.setUpdateOption();
        }

        // 返回
        WasheProto.WasheSeasonMemoryRespMsg.Builder builder = WasheProto.WasheSeasonMemoryRespMsg.newBuilder();
        builder.setRet(0);
        if (seasonMemoryBuilder != null) {
            builder.setMemory(seasonMemoryBuilder);
        }
        player.sendPacket(ClientProtocol.U_WASHE_SEASON_MEMORY, builder);
        return 0;
    }

    // ===================== 好友对战 =====================

    public int friendJoinRoomByCmd(long roomId, int cardId, List<Integer> skillIdList) {
        WasheConfig config = WasheMgr.getWasheConfig();
        WasheUserData userData = getWasheUserData();

        // 盘面技能判断
        Map<Integer, WasheSkillConfig> skillConfigMap = config.getSkillConfigMap();
        Set<Integer> unlockSkill = userData.getUnlockSkill();
        for (int skillId : skillIdList) {
            WasheSkillConfig skillConfig = skillConfigMap.get(skillId);
            if (skillConfig == null) {
                return GameErrorCode.E_WASHE_SKILL_NO_EXIST;
            }
            if (!unlockSkill.contains(skillId)) {
                return GameErrorCode.E_WASHE_SKILL_NO_UNLOCK;
            }
        }

        // 卡片判断
        WasheCardConfig cardConfig = config.getCardConfigMap().get(cardId);
        if (cardConfig == null) {
            return GameErrorCode.E_WASHE_CARD_NO_EXIST;
        }
        if (!userData.getUnlockCard().contains(cardId)) {
            return GameErrorCode.E_WASHE_CARD_NO_UNLOCK;
        }

        WasheProto.ChannelWasheMatchReqMsg.Builder matchDataBuilder = createMatchBuilder(cardId, userData, false, null, eWasheModeType.FriendPk.getValue(), skillIdList);
        // 发送到跨域
        WasheProto.ChannelWasheFriendJoinRoomReqMsg.Builder builder = WasheProto.ChannelWasheFriendJoinRoomReqMsg.newBuilder();
        builder.setMatchData(matchDataBuilder);
        builder.setRoomId(roomId);
        player.sendChannelPacket(ChannelProtocol.N_WASHE_FRIEND_JOIN_ROOM, builder);

        // 保存选择的盘面技能
        userData.setSelectedSkill(skillIdList);

        return 0;
    }

    public int friendQuitRoomByCmd() {
        WasheProto.ChannelWasheUserKeyMsg.Builder builder = WashePb2.parseChannelWasheUserKeyMsg(WasheMgr.getUserKey(getUserId()));
        player.sendChannelPacket(ChannelProtocol.N_WASHE_FRIEND_LEAVE_ROOM, builder);
        return 0;
    }

    public int friendOpenRoomByCmd(int sceneId, int cardId, List<Integer> skillIdList) {
        WasheConfig config = WasheMgr.getWasheConfig();
        WasheUserData userData = getWasheUserData();

        // 盘面机制判断
        WasheSceneConfig sceneConfig = config.getSceneConfigMap().get(sceneId);
        if (sceneConfig == null || !sceneConfig.isOpen() || eWasheSceneType.getEnumByType(sceneId) == null) {
            return GameErrorCode.E_WASHE_SCENE_NO_EXIST;
        }

        // 盘面技能判断
        Map<Integer, WasheSkillConfig> skillConfigMap = config.getSkillConfigMap();
        Set<Integer> unlockSkill = userData.getUnlockSkill();
        for (int skillId : skillIdList) {
            WasheSkillConfig skillConfig = skillConfigMap.get(skillId);
            if (skillConfig == null) {
                return GameErrorCode.E_WASHE_SKILL_NO_EXIST;
            }
            if (!unlockSkill.contains(skillId)) {
                return GameErrorCode.E_WASHE_SKILL_NO_UNLOCK;
            }
        }

        // 卡片判断
        WasheCardConfig cardConfig = config.getCardConfigMap().get(cardId);
        if (cardConfig == null) {
            return GameErrorCode.E_WASHE_CARD_NO_EXIST;
        }
        if (!userData.getUnlockCard().contains(cardId)) {
            return GameErrorCode.E_WASHE_CARD_NO_UNLOCK;
        }

        WasheProto.ChannelWasheMatchReqMsg.Builder matchDataBuilder = createMatchBuilder(cardId, userData, false, null, eWasheModeType.FriendPk.getValue(), skillIdList);

        // 发送到跨域
        WasheProto.ChannelWasheFriendOpenRoomReqMsg.Builder builder = WasheProto.ChannelWasheFriendOpenRoomReqMsg.newBuilder();
        builder.setMatchData(matchDataBuilder);
        builder.setSceneId(sceneId);
        player.sendChannelPacket(ChannelProtocol.N_WASHE_FRIEND_CREATE_ROOM, builder);

        // 保存选择的盘面技能
        userData.setSelectedSkill(skillIdList);

        return 0;
    }

    private WasheProto.ChannelWasheMatchReqMsg.Builder createMatchBuilder(int cardId, WasheUserData userData, boolean practice, Integer practiceScene, int modeId, List<Integer> skillIdList) {
        WasheProto.ChannelWasheMatchReqMsg.Builder matchDataBuilder = WasheProto.ChannelWasheMatchReqMsg.newBuilder();
        matchDataBuilder.setUserKey(WashePb2.parseChannelWasheUserKeyMsg(WasheMgr.getUserKey(getUserId())));
        matchDataBuilder.setUserBaseInfo(PlayerPb.parsePlayerBaseTempMsg(player.getUserInfo()));
        matchDataBuilder.setScore(userData.getScore());
        matchDataBuilder.setCardId(cardId);
        matchDataBuilder.addAllSkillId(skillIdList);
        matchDataBuilder.setIsGuide(userData.isGuide());
        matchDataBuilder.setPlayTimes(userData.getPlayTimes());
        matchDataBuilder.setPractice(practice);
        matchDataBuilder.setAppointSceneId(practiceScene == null ? eWasheSceneType.Empty.getType() : practiceScene);
        matchDataBuilder.setModeId(modeId);
        // 瓦舍外链首次进入好友对战引导
        matchDataBuilder.setFriendGuide(modeId == eWasheModeType.FriendPk.getValue() && userData.isLinkGuide() && player.getLoginLinkType() == eLoginLinkType.Washe.getValue());

        matchDataBuilder.setBoardSkinId(getDecorationIdByType(userData,eWasheDecorationType.BoardSkin.getValue()));
        matchDataBuilder.setAnimationId(getDecorationIdByType(userData,eWasheDecorationType.Animation.getValue()));
        matchDataBuilder.setEffectId(getDecorationIdByType(userData,eWasheDecorationType.Effect.getValue()));

        return matchDataBuilder;
    }

    public int getDecorationIdByType(WasheUserData userData, int type){
        if (userData == null){
            return 0;
        }
        Map<Integer, Integer> decorationMap = userData.getDecorationMap();
        if (decorationMap == null){
            decorationMap = new ConcurrentHashMap<>();
            userData.setDecorationMap(decorationMap);
        }
        if (!decorationMap.containsKey(type)) {
            decorationMap.put(type, 0);
        }
        return decorationMap.get(type);
    }

    public int friendReturnRoomByCmd() {
        WasheProto.ChannelWasheUserKeyMsg.Builder builder = WashePb2.parseChannelWasheUserKeyMsg(WasheMgr.getUserKey(getUserId()));
        player.sendChannelPacket(ChannelProtocol.N_WASHE_FRIEND_ENTER_MY_ROOM, builder);
        return 0;
    }

    public int friendSearchRoomByCmd(long roomId) {
        WasheProto.ChannelWasheFriendSearchRoomReqMsg.Builder builder = WasheProto.ChannelWasheFriendSearchRoomReqMsg.newBuilder();
        builder.setRoomId(roomId);
        builder.setUserKey(WashePb2.parseChannelWasheUserKeyMsg(WasheMgr.getUserKey(getUserId())));
        player.sendChannelPacket(ChannelProtocol.N_WASHE_FRIEND_SEARCH_ROOM, builder);
        return 0;
    }

    public int friendStartGameByCmd() {
        WasheProto.ChannelWasheUserKeyMsg.Builder builder = WashePb2.parseChannelWasheUserKeyMsg(WasheMgr.getUserKey(getUserId()));
        player.sendChannelPacket(ChannelProtocol.N_WASHE_FRIEND_START_GAME, builder);
        return 0;
    }

    public int friendStepOutByCmd() {
        WasheProto.ChannelWasheUserKeyMsg.Builder builder = WashePb2.parseChannelWasheUserKeyMsg(WasheMgr.getUserKey(getUserId()));
        player.sendChannelPacket(ChannelProtocol.N_WASHE_FRIEND_STEP_OUT, builder);
        return 0;
    }

    public int friendChangeCardByCmd(int cardId, List<Integer> skillIdList) {
        WasheConfig config = WasheMgr.getWasheConfig();
        WasheUserData userData = getWasheUserData();

        // 盘面技能判断
        Map<Integer, WasheSkillConfig> skillConfigMap = config.getSkillConfigMap();
        Set<Integer> unlockSkill = userData.getUnlockSkill();
        for (int skillId : skillIdList) {
            WasheSkillConfig skillConfig = skillConfigMap.get(skillId);
            if (skillConfig == null) {
                return GameErrorCode.E_WASHE_SKILL_NO_EXIST;
            }
            if (!unlockSkill.contains(skillId)) {
                return GameErrorCode.E_WASHE_SKILL_NO_UNLOCK;
            }
        }

        // 卡片判断
        WasheCardConfig cardConfig = config.getCardConfigMap().get(cardId);
        if (cardConfig == null) {
            return GameErrorCode.E_WASHE_CARD_NO_EXIST;
        }
        if (!userData.getUnlockCard().contains(cardId)) {
            return GameErrorCode.E_WASHE_CARD_NO_UNLOCK;
        }

        // 发送到跨域
        WasheProto.ChannelWasheFriendInRoomOperateReqMsg.Builder builder = WasheProto.ChannelWasheFriendInRoomOperateReqMsg.newBuilder();
        builder.setUserKey(WashePb2.parseChannelWasheUserKeyMsg(WasheMgr.getUserKey(getUserId())));
        builder.setType(3);
        builder.setChangeCardId(cardId);
        builder.addAllSkillIdList(skillIdList);
        player.sendChannelPacket(ChannelProtocol.N_WASHE_FRIEND_IN_ROOM_OPERATE, builder);

        // 保存选择的盘面技能
        userData.setSelectedSkill(skillIdList);

        return 0;
    }

    public int friendQuickChatByCmd(int chatId) {
        // 发送到跨域
        WasheProto.ChannelWasheFriendInRoomOperateReqMsg.Builder builder = WasheProto.ChannelWasheFriendInRoomOperateReqMsg.newBuilder();
        builder.setUserKey(WashePb2.parseChannelWasheUserKeyMsg(WasheMgr.getUserKey(getUserId())));
        builder.setType(2);
        builder.setQuickChatId(chatId);
        player.sendChannelPacket(ChannelProtocol.N_WASHE_FRIEND_IN_ROOM_OPERATE, builder);
        return 0;
    }

    public int friendReadyByCmd(boolean ready) {
        // 发送到跨域
        WasheProto.ChannelWasheFriendInRoomOperateReqMsg.Builder builder = WasheProto.ChannelWasheFriendInRoomOperateReqMsg.newBuilder();
        builder.setUserKey(WashePb2.parseChannelWasheUserKeyMsg(WasheMgr.getUserKey(getUserId())));
        builder.setType(1);
        builder.setReady(ready);
        player.sendChannelPacket(ChannelProtocol.N_WASHE_FRIEND_IN_ROOM_OPERATE, builder);
        return 0;
    }

    public int friendChangeSceneByCmd(int sceneId) {
        WasheConfig config = WasheMgr.getWasheConfig();

        // 盘面机制判断
        WasheSceneConfig sceneConfig = config.getSceneConfigMap().get(sceneId);
        if (sceneConfig == null || !sceneConfig.isOpen() || eWasheSceneType.getEnumByType(sceneId) == null) {
            return GameErrorCode.E_WASHE_SCENE_NO_EXIST;
        }

        // 发送到跨域
        WasheProto.ChannelWasheFriendInRoomOperateReqMsg.Builder builder = WasheProto.ChannelWasheFriendInRoomOperateReqMsg.newBuilder();
        builder.setUserKey(WashePb2.parseChannelWasheUserKeyMsg(WasheMgr.getUserKey(getUserId())));
        builder.setType(4);
        builder.setChangeSceneId(sceneId);
        player.sendChannelPacket(ChannelProtocol.N_WASHE_FRIEND_IN_ROOM_OPERATE, builder);
        return 0;
    }

    /**
     * 获取锦标赛数据
     */
    public int getJinBiaoPeakDataByCmd(int round) {
        // 发送到跨域
        WasheProto.ChannelWasheGetJinBiaoPeakDataReqMsg.Builder builder = WasheProto.ChannelWasheGetJinBiaoPeakDataReqMsg.newBuilder();
        builder.setUserKey(WashePb2.parseChannelWasheUserKeyMsg(WasheMgr.getUserKey(getUserId())));
        builder.setRound(round);
        player.sendChannelPacket(ChannelProtocol.N_WASHE_GET_JINBIAO_PEAK_DATA, builder);
        return 0;
    }

    public int jinBiaoPeakJoinRoomByCmd(int round, int cardId, List<Integer> skillIdList) {
        WasheConfig config = WasheMgr.getWasheConfig();
        WasheUserData userData = getWasheUserData();

        // 盘面技能判断
        Map<Integer, WasheSkillConfig> skillConfigMap = config.getSkillConfigMap();
        Set<Integer> unlockSkill = userData.getUnlockSkill();
        for (int skillId : skillIdList) {
            WasheSkillConfig skillConfig = skillConfigMap.get(skillId);
            if (skillConfig == null) {
                return GameErrorCode.E_WASHE_SKILL_NO_EXIST;
            }
            if (!unlockSkill.contains(skillId)) {
                return GameErrorCode.E_WASHE_SKILL_NO_UNLOCK;
            }
            if (!skillConfig.isFree()) {
                if (!player.getModule(CurrencyModule.class).currencyIsEnough(PropertyHelper.parseStringToProperty(skillConfig.getItemId() + "=1"))) {
                    return GameErrorCode.E_WASHE_SKILL_NO_ENOUGH;
                }
            }
        }

        // 卡片判断
        WasheCardConfig cardConfig = config.getCardConfigMap().get(cardId);
        if (cardConfig == null) {
            return GameErrorCode.E_WASHE_CARD_NO_EXIST;
        }
        if (!userData.getUnlockCard().contains(cardId)) {
            return GameErrorCode.E_WASHE_CARD_NO_UNLOCK;
        }
        if (!cardConfig.isFree()) {
            if (!player.getModule(CurrencyModule.class).currencyIsEnough(PropertyHelper.parseStringToProperty(cardConfig.getItemId() + "=1"))) {
                // 卡片不够，尝试购买
                if (!buyOneCard(config, cardConfig)) {
                    return GameErrorCode.E_WASHE_CARD_NO_ENOUGH;
                }
            }
        }

        WasheProto.ChannelWasheMatchReqMsg.Builder matchDataBuilder = createMatchBuilder(cardId, userData, false, null, eWasheModeType.JinBiaoPeak.getValue(), skillIdList);
        // 发送到跨域
        WasheProto.ChannelWasheJinBiaoPeakJoinRoomReqMsg.Builder builder = WasheProto.ChannelWasheJinBiaoPeakJoinRoomReqMsg.newBuilder();
        builder.setMatchData(matchDataBuilder);
        builder.setRound(round);
        player.sendChannelPacket(ChannelProtocol.N_WASHE_JINBIAO_PEAK_JOIN_ROOM, builder);

        // 保存选择的盘面技能
        userData.setSelectedSkill(skillIdList);

        return 0;
    }

    public int jinBiaoPeakChangeCardByCmd(int cardId, List<Integer> skillIdList) {
        WasheConfig config = WasheMgr.getWasheConfig();
        WasheUserData userData = getWasheUserData();

        // 盘面技能判断
        Map<Integer, WasheSkillConfig> skillConfigMap = config.getSkillConfigMap();
        Set<Integer> unlockSkill = userData.getUnlockSkill();
        for (int skillId : skillIdList) {
            WasheSkillConfig skillConfig = skillConfigMap.get(skillId);
            if (skillConfig == null) {
                return GameErrorCode.E_WASHE_SKILL_NO_EXIST;
            }
            if (!unlockSkill.contains(skillId)) {
                return GameErrorCode.E_WASHE_SKILL_NO_UNLOCK;
            }
            if (!skillConfig.isFree()) {
                if (!player.getModule(CurrencyModule.class).currencyIsEnough(PropertyHelper.parseStringToProperty(skillConfig.getItemId() + "=1"))) {
                    return GameErrorCode.E_WASHE_SKILL_NO_ENOUGH;
                }
            }
        }

        // 卡片判断
        WasheCardConfig cardConfig = config.getCardConfigMap().get(cardId);
        if (cardConfig == null) {
            return GameErrorCode.E_WASHE_CARD_NO_EXIST;
        }
        if (!userData.getUnlockCard().contains(cardId)) {
            return GameErrorCode.E_WASHE_CARD_NO_UNLOCK;
        }

        if (!cardConfig.isFree()) {
            if (!player.getModule(CurrencyModule.class).currencyIsEnough(PropertyHelper.parseStringToProperty(cardConfig.getItemId() + "=1"))) {
                // 卡片不够，尝试购买
                if (!buyOneCard(config, cardConfig)) {
                    return GameErrorCode.E_WASHE_CARD_NO_ENOUGH;
                }
            }
        }

        // 发送到跨域
        WasheProto.ChannelWasheJinBiaoPeakInRoomOperateReqMsg.Builder builder = WasheProto.ChannelWasheJinBiaoPeakInRoomOperateReqMsg.newBuilder();
        builder.setUserKey(WashePb2.parseChannelWasheUserKeyMsg(WasheMgr.getUserKey(getUserId())));
        builder.setType(1);
        builder.setChangeCardId(cardId);
        builder.addAllSkillIdList(skillIdList);
        player.sendChannelPacket(ChannelProtocol.N_WASHE_JINBIAO_PEAK_IN_ROOM_OPERATE, builder);

        // 保存选择的盘面技能
        userData.setSelectedSkill(skillIdList);

        return 0;
    }

    public int jinBiaoPeakQuitRoomByCmd() {
        WasheProto.ChannelWasheUserKeyMsg.Builder builder = WashePb2.parseChannelWasheUserKeyMsg(WasheMgr.getUserKey(getUserId()));
        player.sendChannelPacket(ChannelProtocol.N_WASHE_JINBIAO_PEAK_LEAVE_ROOM, builder);
        return 0;
    }

    public int jinBiaoPeakReturnRoomByCmd() {
        WasheProto.ChannelWasheUserKeyMsg.Builder builder = WashePb2.parseChannelWasheUserKeyMsg(WasheMgr.getUserKey(getUserId()));
        player.sendChannelPacket(ChannelProtocol.N_WASHE_JINBIAO_PEAK_ENTER_MY_ROOM, builder);
        return 0;
    }

    /**
     * 获取锦标赛记录
     */
    public int getPeakBattleRecordByCmd(long userId, long serverId) {
        // 发送到跨域
        WasheProto.ChannelWasheGetPeakBattleRecordReqMsg.Builder builder = WasheProto.ChannelWasheGetPeakBattleRecordReqMsg.newBuilder();
        builder.setUserKey(WashePb2.parseChannelWasheUserKeyMsg(WasheMgr.getUserKey(getUserId())));
        builder.setUserId(userId);
        builder.setServerId(serverId);
        player.sendChannelPacket(ChannelProtocol.N_WASHE_GET_PEAK_BATTLE_RECORD, builder);
        return 0;
    }

    /**
     * 请求阶段性奖励信息
     */
    public int getStageRewardInfoByCmd() {
        WasheUserJinBiaoData jinBiaoData = getWasheUserJinBiaoData();
        if (jinBiaoData == null) {
            return GameErrorCode.E_WASHE_JIN_BIAO_DATA_NOT_FOUND;
        }
        // 发送到跨域
        WasheProto.ChannelWasheGetStageRewardInfoReqMsg.Builder builder = WasheProto.ChannelWasheGetStageRewardInfoReqMsg.newBuilder();
        builder.setUserKey(WashePb2.parseChannelWasheUserKeyMsg(WasheMgr.getUserKey(getUserId())));
        builder.addAllHadRewardStage(jinBiaoData.getHadRewardStageList());
        player.sendChannelPacket(ChannelProtocol.N_WASHE_GET_STAGE_REWARD_INFO, builder);
        return 0;
    }

    /**
     * 请求领取阶段性奖励
     */
    public int getStageRewardByCmd() {
        WasheUserJinBiaoData jinBiaoData = getWasheUserJinBiaoData();
        if (jinBiaoData == null) {
            return GameErrorCode.E_WASHE_JIN_BIAO_DATA_NOT_FOUND;
        }
        // 发送到跨域
        WasheProto.ChannelWasheGetStageRewardReqMsg.Builder builder = WasheProto.ChannelWasheGetStageRewardReqMsg.newBuilder();
        builder.setUserKey(WashePb2.parseChannelWasheUserKeyMsg(WasheMgr.getUserKey(getUserId())));
        player.sendChannelPacket(ChannelProtocol.N_WASHE_GET_STAGE_REWARD, builder);
        return 0;
    }

    private void notifyWashePlayTimes(int times){
        player.notifyListener(eGamePlayerEventType.PlayWasheTimes.getValue(), times);
        player.notifyListener(eGamePlayerEventType.WaSheDoneTimes.getValue(), times);
        //平台接口加次数
        player.getModule(XiaoMianModule.class).addJoinWaSheTimes(times);
    }

    /**
     * 请求领取分享奖励
     */
    public int getShareRewardByCmd() {
        WasheUserData userData = getWasheUserData();
        if (userData == null) {
            return GameErrorCode.E_WASHE_NO_SYSTEM;
        }
        WasheConfig washeConfig = WasheMgr.getWasheConfig();
        if (washeConfig == null) {
            return GameErrorCode.E_WASHE_NO_SYSTEM;
        }
        int todayZeroTime = DateHelper.getTodayZeroTime();
        if (todayZeroTime <= userData.getShareRewardTime()) {
            return GameErrorCode.E_WASHE_ALREADY_GET_SHARE_REWARD;
        }
        userData.setShareRewardTime(todayZeroTime);
        // 获取奖励
        Property property = PropertyHelper.parseStringToProperty(GameConfig.WASHEPVP_SHARE_REWARD);
        player.getModule(CurrencyModule.class).addCurrency(property, eLogMoneyType.Washe, eLogMoneyType.WasheShareReward);
        // 返回
        WasheProto.WasheShareRewardRespMsg.Builder builder = WasheProto.WasheShareRewardRespMsg.newBuilder();
        builder.setRet(0);
        builder.setReward(PropertyHelper.parsePropertyToString(property));
        builder.setShareRewardTime(userData.getShareRewardTime());
        player.sendPacket(ClientProtocol.U_WASHE_GET_SHARE_REWARD, builder);
        return 0;
    }

    /**
     * 更换皮肤
     */
    public int changeDecoration(int type,int decorationId) {
        WasheUserData userData = getWasheUserData();
        if (userData == null) {
            return GameErrorCode.E_WASHE_NO_SYSTEM;
        }
        WasheConfig washeConfig = WasheMgr.getWasheConfig();
        if (washeConfig == null) {
            return GameErrorCode.E_WASHE_NO_SYSTEM;
        }
        int decorationIdByType = getDecorationIdByType(userData, type);
        if (decorationId == decorationIdByType) {
            return GameErrorCode.E_WASHE_ALREADY_USE_THIS_DECORATION;
        }
        if (decorationId != 0){
            Property property = new Property(decorationId, 1);
            if(!player.getModule(CurrencyModule.class).currencyIsEnough(property)){
                return GameErrorCode.E_WASHE_DECORATION_NOT_UNLOCK;
            }
            if (type == eWasheDecorationType.BoardSkin.getValue()) {
                if (!GoodsMgr.isWaSheBoard(decorationId)) {
                    return GameErrorCode.E_WASHE_DECORATION_TYPE_ERROR;
                }
            } else if (type == eWasheDecorationType.Animation.getValue()) {
                if (!GoodsMgr.isWaSheSettleAnimation(decorationId)) {
                    return GameErrorCode.E_WASHE_DECORATION_TYPE_ERROR;
                }
            } else if (type == eWasheDecorationType.Effect.getValue()) {
                if (!GoodsMgr.isWaSheEliminateEffect(decorationId)) {
                    return GameErrorCode.E_WASHE_DECORATION_TYPE_ERROR;
                }
            } else {
                return GameErrorCode.E_WASHE_DECORATION_NOT_UNLOCK;
            }

        }

        userData.setDecorationByType(type, decorationId);
        WasheProto.WasheChangeDecorationRespMsg.Builder respMsg = WasheProto.WasheChangeDecorationRespMsg.newBuilder();
        respMsg.setRet(0);
        respMsg.setUseBoardSkin(getDecorationIdByType(userData, eWasheDecorationType.BoardSkin.getValue()));
        respMsg.setUseAnimation(getDecorationIdByType(userData, eWasheDecorationType.Animation.getValue()));
        respMsg.setUseEffect(getDecorationIdByType(userData, eWasheDecorationType.Effect.getValue()));
        player.sendPacket(ClientProtocol.U_WASHE_CHANGE_DECORATION,respMsg);
        return 0;
    }

}
